Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Eileen M. Uchitelle eileencodes.com @eileencodes

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

What is Ruby on Rails?

Slide 8

Slide 8 text

Rails is modular, but 
 not fractured

Slide 9

Slide 9 text

Rails is designed to have agnostic interfaces

Slide 10

Slide 10 text

Rails is extracted from applications

Slide 11

Slide 11 text

Rails is made of 
 simple and aesthetic APIs

Slide 12

Slide 12 text

Rails is a framework that takes on complexity to empower you

Slide 13

Slide 13 text

How Rails components are structured

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Naming Convention Active vs Action

Slide 16

Slide 16 text

Active Record Active Support Active Model Active Job Active Storage BACKEND NAMING CONVENTION

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Architecture & Patterns of Rails components

Slide 20

Slide 20 text

Architecture & Patterns the role of Railties

Slide 21

Slide 21 text

👩💻 Application

Slide 22

Slide 22 text

👩💻 Application Register hooks

Slide 23

Slide 23 text

👩💻 Application Register hooks Load components

Slide 24

Slide 24 text

👩💻 Application Register hooks Load components Run hooks

Slide 25

Slide 25 text

# railtie.rb initializer "initializer.name" do # do something at initialization end

Slide 26

Slide 26 text

# railties/lib/rails/application.rb def initializer(name, opts = {}, &block) self.class.initializer(name, opts, &block) end

Slide 27

Slide 27 text

# railtie.rb initializer "initializer.name" do |app| app.do_something app.config.do_something end

Slide 28

Slide 28 text

# railtie.rb initializer "initializer.name" do ActiveSupport.on_load(:active_record) do # do something at initialization end end

Slide 29

Slide 29 text

# 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

Slide 30

Slide 30 text

# 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

Slide 31

Slide 31 text

# 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

Slide 32

Slide 32 text

# 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

Slide 33

Slide 33 text

# 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

Slide 34

Slide 34 text

# 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

Slide 35

Slide 35 text

# activejob/lib/active_job/railtie.rb initializer "active_model.deprecator", before: :load_environment_config do |app| app.deprecators[:active_model] = ActiveModel.deprecator end

Slide 36

Slide 36 text

# activejob/lib/active_job/railtie.rb initializer "active_model.deprecator", before: :load_environment_config do |app| app.deprecators[:active_model] = ActiveModel.deprecator end

Slide 37

Slide 37 text

• Railties are the core of the framework

Slide 38

Slide 38 text

• Railties are the core of the framework • Railties control load order and when hooks should be run

Slide 39

Slide 39 text

• 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

Slide 40

Slide 40 text

Architecture & Patterns Agnostic interfaces

Slide 41

Slide 41 text

if connection.is_a?(PostgresqlAdapter) # ... elsif connection.is_a?(Mysql2Adapter) # ... elsif connection.is_a?(TrilogyAdapter) # ... elsif connection.is_?(Sqlite3Adapter) # ... else # ... end

Slide 42

Slide 42 text

if connection.is_a?(PostgresqlAdapter) # ... elsif connection.is_a?(Mysql2Adapter) # ... elsif connection.is_a?(TrilogyAdapter) # ... elsif connection.is_?(Sqlite3Adapter) # ... else # ... end ❌

Slide 43

Slide 43 text

module ActiveRecord module ConnectionAdapters class AbstractAdapter # define interface end end end

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

connection.supports_foreign_keys? => true

Slide 46

Slide 46 text

class AbstractAdapter def supports_foreign_keys? false end end

Slide 47

Slide 47 text

class AbstractAdapter def supports_foreign_keys? false end end class PostgresqlAdapter < AbstractAdapter def supports_foreign_keys? true end end

Slide 48

Slide 48 text

# activestorage/lib/active_storage/service.rb module ActiveStorage class Service def delete(key) raise NotImplementedError end end end

Slide 49

Slide 49 text

# 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

Slide 50

Slide 50 text

@service.delete(key)

Slide 51

Slide 51 text

• Consistent interface for all supported libraries

Slide 52

Slide 52 text

• Consistent interface for all supported libraries • Simpli fi es Rails code to avoid using `is_a?`

Slide 53

Slide 53 text

• 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

Slide 54

Slide 54 text

• 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

Slide 55

Slide 55 text

Architecture & Patterns Metaprogramming

Slide 56

Slide 56 text

class Post < ApplicationRecord has_many :comments end class Comment < ApplicationRecord belongs_to :post end

Slide 57

Slide 57 text

post = Post.first post.comments => [#, #]

Slide 58

Slide 58 text

post = Post.first post.method(:comments).source_location

Slide 59

Slide 59 text

post = Post.first post.method(:comments).source_location => ["rails/activerecord/lib/ active_record/associations/builder/ association.rb", 103]

Slide 60

Slide 60 text

# 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

Slide 61

Slide 61 text

# 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

Slide 62

Slide 62 text

# 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

Slide 63

Slide 63 text

Post::GeneratedAssociationMethods

Slide 64

Slide 64 text

# 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

Slide 65

Slide 65 text

# 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

Slide 66

Slide 66 text

# 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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

• Powerful tool that enables us to build beautiful, simple APIs • Hides complexity from your application

Slide 69

Slide 69 text

• Powerful tool that enables us to build beautiful, simple APIs • Hides complexity from your application • Where "Rails Magic" comes from

Slide 70

Slide 70 text

Maintaining Rails Why I work on it

Slide 71

Slide 71 text

2010 Introduced to Rails

Slide 72

Slide 72 text

2010 Introduced to Rails 2011 Big Nerd Ranch

Slide 73

Slide 73 text

2010 Introduced to Rails 2011 Big Nerd Ranch 2014 1st conference 1st contribution

Slide 74

Slide 74 text

2010 Introduced to Rails 2011 Big Nerd Ranch 2014 1st conference 1st contribution 2015 First RailsConf

Slide 75

Slide 75 text

2010 Introduced to Rails 2011 Big Nerd Ranch 2014 1st conference 1st contribution 2015 First RailsConf 2017 Join Rails Core

Slide 76

Slide 76 text

2010 Introduced to Rails 2011 Big Nerd Ranch 2014 1st conference 1st contribution 2015 First RailsConf 2017 Join Rails Core 2023 Rails is 20!

Slide 77

Slide 77 text

I work on Rails to advance the framework

Slide 78

Slide 78 text

I work on Rails to ensure applications can stay on Rails

Slide 79

Slide 79 text

I work on Rails to build a stronger community

Slide 80

Slide 80 text

I work on Rails to have an impact on the future

Slide 81

Slide 81 text

Rails is so much more than just a framework

Slide 82

Slide 82 text

Rails is inspiring

Slide 83

Slide 83 text

Rails is empowering

Slide 84

Slide 84 text

Rails is imperfect

Slide 85

Slide 85 text

Rails is the applications we build

Slide 86

Slide 86 text

Rails is the team behind it

Slide 87

Slide 87 text

Rails is the community

Slide 88

Slide 88 text

Rails is magic

Slide 89

Slide 89 text

Thank You!

Slide 90

Slide 90 text

Eileen M. Uchitelle eileencodes.com @eileencodes Senior Staff Engineer @ Shopify Rails Core Team