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

[Brighton Ruby 2023] The Magic of Rails

[Brighton Ruby 2023] 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

June 30, 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. Hello Brighton! I'm


    Eileen M. Uchitelle
    @eileencodes


    @[email protected]


    @eileencodes.bsky.social


    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. # activejob/lib/active_job/railtie.rb


    initializer "active_job.logger" do


    ActiveSupport.on_load(:active_job) {


    self.logger = ::Rails.logger


    }


    end

    View Slide

  33. # 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

  34. # 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

  35. • Railties are the core of
    the framework

    View Slide

  36. • Railties are the core of
    the framework


    • Railties control load
    order and when hooks
    should be run

    View Slide

  37. • 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

  38. Architecture & Patterns


    Agnostic interfaces

    View Slide

  39. if connection.is_a?(PostgresqlAdapter)


    # ...


    elsif connection.is_a?(Mysql2Adapter)


    # ...


    elsif connection.is_a?(TrilogyAdapter)


    # ...


    elsif connection.is_?(Sqlite3Adapter)


    # ...


    else


    # ...


    end

    View Slide

  40. if connection.is_a?(PostgresqlAdapter)


    # ...


    elsif connection.is_a?(Mysql2Adapter)


    # ...


    elsif connection.is_a?(TrilogyAdapter)


    # ...


    elsif connection.is_?(Sqlite3Adapter)


    # ...


    else


    # ...


    end

    View Slide

  41. module ActiveRecord


    module ConnectionAdapters


    class AbstractAdapter


    # define interface


    end


    end


    end


    View Slide

  42. 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

  43. connection.supports_foreign_keys?


    => true


    View Slide

  44. class AbstractAdapter


    def supports_foreign_keys?


    false


    end


    end

    View Slide

  45. class AbstractAdapter


    def supports_foreign_keys?


    false


    end


    end


    class PostgresqlAdapter < AbstractAdapter


    def supports_foreign_keys?


    true


    end


    end


    View Slide

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


    module ActiveStorage


    class Service


    def delete(key)


    raise NotImplementedError


    end


    end


    end


    View Slide

  47. # 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

  48. @service.delete(key)


    View Slide

  49. • Consistent interface for
    all supported libraries

    View Slide

  50. • Consistent interface for
    all supported libraries


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

    View Slide

  51. • 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

  52. • 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

  53. Architecture & Patterns


    Metaprogramming

    View Slide

  54. class Post < ApplicationRecord


    has_many :comments


    end


    class Comment < ApplicationRecord


    belongs_to :post


    end

    View Slide

  55. post = Post.first


    post.comments


    => [#,


    #]

    View Slide

  56. post = Post.first


    post.method(:comments).source_location

    View Slide

  57. post = Post.first


    post.method(:comments).source_location


    => ["rails/activerecord/lib/


    active_record/associations/builder/


    association.rb", 103]


    View Slide

  58. # 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

  59. # 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

  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. Post::GeneratedAssociationMethods

    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. # 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

  64. # 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

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

    View Slide

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


    • Hides complexity from
    your application

    View Slide

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


    • Hides complexity from
    your application


    • Where "Rails Magic"
    comes from

    View Slide

  68. Maintaining Rails


    Why I work on it

    View Slide

  69. 2010


    Introduced


    to Rails

    View Slide

  70. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch

    View Slide

  71. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution

    View Slide

  72. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution
    2015


    First RailsConf

    View Slide

  73. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution
    2015


    First RailsConf
    2017


    Join Rails Core

    View Slide

  74. 2010


    Introduced


    to Rails
    2011


    Big Nerd Ranch
    2014


    1st conference


    1st contribution
    2015


    First RailsConf
    2017


    Join Rails Core
    2023


    Today

    View Slide

  75. I work on Rails to


    advance the


    framework

    View Slide

  76. I work on Rails to


    ensure applications


    can stay on Rails

    View Slide

  77. I work on Rails to


    build a stronger


    community

    View Slide

  78. I work on Rails to


    have an impact


    on the future

    View Slide

  79. Rails is so much more


    than just a framework

    View Slide

  80. Rails is


    inspiring

    View Slide

  81. Rails is


    empowering

    View Slide

  82. Rails is


    imperfect

    View Slide

  83. Rails is


    the applications we build

    View Slide

  84. Rails is


    the team behind it

    View Slide

  85. Rails is


    the community

    View Slide

  86. Rails is magic

    View Slide

  87. Thank You!


    View Slide

  88. Eileen M. Uchitelle
    @eileencodes


    @[email protected]


    @eileencodes.bsky.social


    View Slide