Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails

[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails

Today we're going to explore the magic of Rails. We'll look at the philosophy behind the framework as well as the overall structure of the components. We'll explore some of the common patterns that Rails uses to build agnostic and beautiful interfaces, and the techniques it implements to hide complexity so you can focus building your application. By the end of this talk you'll feel more confident navigating the Rails codebase and better understand the patterns it uses to create the framework we all know and love. But Rails is so much more than its design and architecture. We'll dive into my motivations for working on the framework and why the community is so important to the long term success of Rails.

Eileen M. Uchitelle

October 05, 2023
Tweet

More Decks by Eileen M. Uchitelle

Other Decks in Programming

Transcript

  1. The Magic of Rails
    exploring the principles & techniques
    behind the framework

    View Slide

  2. View Slide

  3. Eileen M. Uchitelle
    eileencodes.com


    @eileencodes

    View Slide

  4. View Slide

  5. View Slide

  6. The Magic of Rails
    exploring the principles & techniques
    behind the framework

    View Slide

  7. What is


    Ruby on Rails?

    View Slide

  8. Rails is


    modular, but

    not fractured

    View Slide

  9. Rails is


    designed to
    have agnostic
    interfaces

    View Slide

  10. Rails is


    extracted from
    applications

    View Slide

  11. Rails is


    made of

    simple and
    aesthetic APIs

    View Slide

  12. Rails is


    a framework
    that takes on
    complexity to
    empower you

    View Slide

  13. How Rails components


    are structured

    View Slide

  14. RUBY ON RAILS
    Active Record
    Active Support
    Active Model
    Active Job
    Active Storage
    Action Mailer
    Action Pack Action View
    Action Cable
    Action Text
    Action Mailbox
    Railties

    View Slide

  15. Naming Convention


    Active vs Action

    View Slide

  16. Active Record


    Active Support


    Active Model


    Active Job


    Active Storage
    BACKEND
    NAMING CONVENTION

    View Slide

  17. USER FACING
    Active Record


    Active Support


    Active Model


    Active Job


    Active Storage
    BACKEND
    NAMING CONVENTION
    Action Mailer


    Action Pack


    Action View


    Action Cable


    Action Text


    Action Mailbox
    USER FACING

    View Slide

  18. Active Record


    Active Support


    Active Model


    Active Job


    Active Storage
    Action Mailer


    Action Pack


    Action View


    Action Cable


    Action Text


    Action Mailbox
    BACKEND USER FACING
    Railties
    GLUE
    NAMING CONVENTION

    View Slide

  19. Architecture & Patterns


    of Rails components

    View Slide

  20. Architecture & Patterns


    the role of Railties

    View Slide

  21. 👩💻
    Application

    View Slide

  22. 👩💻
    Application Register hooks

    View Slide

  23. 👩💻
    Application Register hooks Load components

    View Slide

  24. 👩💻
    Application Register hooks Load components Run hooks

    View Slide

  25. # railtie.rb


    initializer "initializer.name" do


    # do something at initialization


    end

    View Slide

  26. # railties/lib/rails/application.rb


    def initializer(name, opts = {}, &block)


    self.class.initializer(name, opts, &block)


    end

    View Slide

  27. # railtie.rb


    initializer "initializer.name" do |app|


    app.do_something


    app.config.do_something


    end

    View Slide

  28. # railtie.rb


    initializer "initializer.name" do


    ActiveSupport.on_load(:active_record) do


    # do something at initialization


    end


    end

    View Slide

  29. # activerecord/lib/active_record/railtie.rb


    initializer "active_record.initialize_database" do


    ActiveSupport.on_load(:active_record) do


    self.configurations =


    Rails.application.config.database_configuration




    establish_connection


    end


    end

    View Slide

  30. # activerecord/lib/active_record/railtie.rb


    initializer "active_record.initialize_database" do


    ActiveSupport.on_load(:active_record) do


    self.configurations =


    Rails.application.config.database_configuration




    establish_connection


    end


    end

    View Slide

  31. # activerecord/lib/active_record/railtie.rb


    initializer "active_record.initialize_database" do


    ActiveSupport.on_load(:active_record) do


    self.configurations =


    Rails.application.config.database_configuration




    establish_connection


    end


    end

    View Slide

  32. # activerecord/lib/active_record/railtie.rb


    initializer "active_record.log_runtime" do


    require "active_record/railties/controller_runtime"


    ActiveSupport.on_load(:action_controller) do


    include ActiveRecord::Railties::ControllerRuntime


    end


    require "active_record/railties/job_runtime"


    ActiveSupport.on_load(:active_job) do


    include ActiveRecord::Railties::JobRuntime


    end


    end


    View Slide

  33. # activerecord/lib/active_record/railtie.rb


    initializer "active_record.log_runtime" do


    require "active_record/railties/controller_runtime"


    ActiveSupport.on_load(:action_controller) do


    include ActiveRecord::Railties::ControllerRuntime


    end


    require "active_record/railties/job_runtime"


    ActiveSupport.on_load(:active_job) do


    include ActiveRecord::Railties::JobRuntime


    end


    end


    View Slide

  34. # activerecord/lib/active_record/railtie.rb


    initializer "active_record.log_runtime" do


    require "active_record/railties/controller_runtime"


    ActiveSupport.on_load(:action_controller) do


    include ActiveRecord::Railties::ControllerRuntime


    end


    require "active_record/railties/job_runtime"


    ActiveSupport.on_load(:active_job) do


    include ActiveRecord::Railties::JobRuntime


    end


    end


    View Slide

  35. # activejob/lib/active_job/railtie.rb


    initializer "active_model.deprecator",


    before: :load_environment_config do |app|




    app.deprecators[:active_model] =


    ActiveModel.deprecator


    end


    View Slide

  36. # activejob/lib/active_job/railtie.rb


    initializer "active_model.deprecator",


    before: :load_environment_config do |app|




    app.deprecators[:active_model] =


    ActiveModel.deprecator


    end


    View Slide

  37. • Railties are the core of
    the framework

    View Slide

  38. • Railties are the core of
    the framework


    • Railties control load
    order and when hooks
    should be run

    View Slide

  39. • Railties are the core of
    the framework


    • Railties control load
    order and when hooks
    should be run


    • Enables components to
    work together without
    adding dependencies

    View Slide

  40. Architecture & Patterns


    Agnostic interfaces

    View Slide

  41. if connection.is_a?(PostgresqlAdapter)


    # ...


    elsif connection.is_a?(Mysql2Adapter)


    # ...


    elsif connection.is_a?(TrilogyAdapter)


    # ...


    elsif connection.is_?(Sqlite3Adapter)


    # ...


    else


    # ...


    end

    View Slide

  42. if connection.is_a?(PostgresqlAdapter)


    # ...


    elsif connection.is_a?(Mysql2Adapter)


    # ...


    elsif connection.is_a?(TrilogyAdapter)


    # ...


    elsif connection.is_?(Sqlite3Adapter)


    # ...


    else


    # ...


    end

    View Slide

  43. module ActiveRecord


    module ConnectionAdapters


    class AbstractAdapter


    # define interface


    end


    end


    end


    View Slide

  44. module ActiveRecord


    module ConnectionAdapters


    class AbstractAdapter


    # define interface


    end


    end


    end


    module ActiveRecord


    module ConnectionAdapters


    class PostgresqlAdapter < AbstractAdapter


    # inherit or redefine interface


    end


    end


    end

    View Slide

  45. connection.supports_foreign_keys?


    => true


    View Slide

  46. class AbstractAdapter


    def supports_foreign_keys?


    false


    end


    end

    View Slide

  47. class AbstractAdapter


    def supports_foreign_keys?


    false


    end


    end


    class PostgresqlAdapter < AbstractAdapter


    def supports_foreign_keys?


    true


    end


    end


    View Slide

  48. # activestorage/lib/active_storage/service.rb


    module ActiveStorage


    class Service


    def delete(key)


    raise NotImplementedError


    end


    end


    end


    View Slide

  49. # activestorage/lib/active_storage/service/gcs_service.rb


    class ActiveStorage


    class Service::GCSService < Service


    def delete(key)


    instrument :delete, key: key do


    file_for(key).delete


    rescue Google::Cloud::NotFoundError


    # Ignore files already deleted


    end


    end


    end


    end

    View Slide

  50. @service.delete(key)


    View Slide

  51. • Consistent interface for
    all supported libraries

    View Slide

  52. • Consistent interface for
    all supported libraries


    • Simpli
    fi
    es Rails code to
    avoid using `is_a?`

    View Slide

  53. • Consistent interface for
    all supported libraries


    • Simpli
    fi
    es Rails code to
    avoid using `is_a?`


    • Makes it easy for apps to
    swap out adapters /
    services

    View Slide

  54. • Consistent interface for
    all supported libraries


    • Simpli
    fi
    es Rails code to
    avoid using `is_a?`


    • Makes it easy for apps to
    swap out adapters /
    services


    • Lowers the maintenance
    burden

    View Slide

  55. Architecture & Patterns


    Metaprogramming

    View Slide

  56. class Post < ApplicationRecord


    has_many :comments


    end


    class Comment < ApplicationRecord


    belongs_to :post


    end

    View Slide

  57. post = Post.first


    post.comments


    => [#,


    #]

    View Slide

  58. post = Post.first


    post.method(:comments).source_location

    View Slide

  59. post = Post.first


    post.method(:comments).source_location


    => ["rails/activerecord/lib/


    active_record/associations/builder/


    association.rb", 103]


    View Slide

  60. # activerecord/lib/active_record/associations/builder/
    association.rb


    class ActiveRecord::Associations::Builder


    class Association


    def self.define_readers(mixin, name)


    mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1


    def #{name}


    association(:#{name}).reader


    end


    CODE


    end


    end


    end


    View Slide

  61. # activerecord/lib/active_record/associations/builder/
    association.rb


    class ActiveRecord::Associations::Builder


    class Association


    def self.define_readers(mixin, name)


    mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1


    def #{name}


    association(:#{name}).reader


    end


    CODE


    end


    end


    end


    View Slide

  62. # activerecord/lib/active_record/associations/builder/
    association.rb


    class ActiveRecord::Associations::Builder


    class Association


    def self.define_readers(mixin, name)


    mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1


    def #{name}


    association(:#{name}).reader


    end


    CODE


    end


    end


    end


    View Slide

  63. Post::GeneratedAssociationMethods

    View Slide

  64. # activerecord/lib/active_record/associations/builder/
    association.rb


    class ActiveRecord::Associations::Builder


    class Association


    def self.define_readers(mixin, name)


    mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1


    def #{name}


    association(:#{name}).reader


    end


    CODE


    end


    end


    end


    View Slide

  65. # activerecord/lib/active_record/associations/builder/
    association.rb


    class ActiveRecord::Associations::Builder


    class Association


    def self.define_writers(mixin, name)


    mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1


    def #{name}=(value)


    association(:#{name}).writer(value)


    end


    CODE


    end


    end


    end


    View Slide

  66. # activerecord/lib/active_record/associations/builder/
    association.rb


    class ActiveRecord::Associations::Builder


    class Association


    def self.define_writers(mixin, name)


    mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1


    def #{name}=(value)


    association(:#{name}).writer(value)


    end


    CODE


    end


    end


    end


    View Slide

  67. • Powerful tool that
    enables us to build
    beautiful, simple APIs

    View Slide

  68. • Powerful tool that
    enables us to build
    beautiful, simple APIs


    • Hides complexity from
    your application

    View Slide

  69. • Powerful tool that
    enables us to build
    beautiful, simple APIs


    • Hides complexity from
    your application


    • Where "Rails Magic"
    comes from

    View Slide

  70. Maintaining Rails


    Why I work on it

    View Slide

  71. 2010


    Introduced


    to Rails

    View Slide

  72. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch

    View Slide

  73. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution

    View Slide

  74. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution
    2015


    First RailsConf

    View Slide

  75. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution
    2015


    First RailsConf
    2017


    Join Rails Core

    View Slide

  76. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution
    2015


    First RailsConf
    2017


    Join Rails Core
    2023


    Rails is 20!

    View Slide

  77. I work on Rails to


    advance the


    framework

    View Slide

  78. I work on Rails to


    ensure applications


    can stay on Rails

    View Slide

  79. I work on Rails to


    build a stronger


    community

    View Slide

  80. I work on Rails to


    have an impact


    on the future

    View Slide

  81. Rails is so much more


    than just a framework

    View Slide

  82. Rails is


    inspiring

    View Slide

  83. Rails is


    empowering

    View Slide

  84. Rails is


    imperfect

    View Slide

  85. Rails is


    the applications we build

    View Slide

  86. Rails is


    the team behind it

    View Slide

  87. Rails is


    the community

    View Slide

  88. Rails is magic

    View Slide

  89. Thank You!


    View Slide

  90. Eileen M. Uchitelle
    eileencodes.com


    @eileencodes


    Senior Staff Engineer @ Shopify


    Rails Core Team

    View Slide