Slide 1

Slide 1 text

http://www.flickr.com/photos/xt0ph3r/3591242324 modularizing rails apps kevin shekleton @kpshek

Slide 2

Slide 2 text

@kpshek

Slide 3

Slide 3 text

Modularizing
 Rails Apps

Slide 4

Slide 4 text

Oregon

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

2007 Rails 2.0

Slide 7

Slide 7 text

class Plugin • The junk drawer of Rails apps • Code copied into
 your_app/vendor/plugins • Often managed via rake tasks or git submodules • Encourages local editing http://www.flickr.com/photos/listener42/3488807301

Slide 8

Slide 8 text

2007 Rails 2.0 2009 Rails 2.3 Full engines

Slide 9

Slide 9 text

2005 2007 Rails 2.0 2009 Rails 2.3 Engine concept introduced Full engines

Slide 10

Slide 10 text

2005: Rails Engines Plugin

Slide 11

Slide 11 text

2005: Engines are not evil but distracting 2009: Engines are the future! (emphasis mine)

Slide 12

Slide 12 text

Russian Doll Pattern • Y. Katz, C. Lerche
 RailsConf 2009
 http://vimeo.com/4611379 • Build reusable slices not core to your app and embed it • Apps within apps • Implemented earlier as
 Merb slices http://www.flickr.com/photos/johnkay/3539939004

Slide 13

Slide 13 text

http://www.flickr.com/photos/icebone/2876059462 Full Engines

Slide 14

Slide 14 text

Full Engine $ rails plugin new \
 name --full A reusable app that fully integrates into your app MVC, routes, assets, etc defined in the engine are automatically available in your app http://www.flickr.com/photos/scania/2869106546

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Beware of Collisions

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Full engines 2005 2007 Rails 2.0 2009 Rails 2.3 2010 Rails 3.0 Engine concept introduced Railties Overhauled

Slide 20

Slide 20 text

Railties http://www.flickr.com/photos/perry-pics/7721695188

Slide 21

Slide 21 text

Railtie Power • Add rake tasks • Add generators • Hook into the Rails console load • Hook into the various Rails lifecycle events (before/after_initialize, to_prepare, etc) https://blog.engineyard.com/2010/extending-rails-3-with-railties

Slide 22

Slide 22 text

# See Railtie::Configuration config.to_prepare { ... } module Awesome end class Railtie < Rails::Railtie end rake_tasks do load ‘/awesome.tasks’ end initializer ‘awesome.configure’ do |app| # do awesome things like # subscribe to ActiveSupport::Notifications end Creating a Railtie

Slide 23

Slide 23 text

•# Called before the app’s config is loaded config.before_configuration = {...} •# Called before Rails has been initialized config.before_initialize = {...} •# Called before app classes are loaded config.before_eager_load = {...} Railtie Initializer Hooks

Slide 24

Slide 24 text

•# Called after app classes are loaded config.to_prepare = {...} •# Called after Rails has been initialized config.after_initialize = {...} Railtie Initializer Hooks (cont)

Slide 25

Slide 25 text

Using a Railtie # Gemfile of your app gem ‘awesome’, ’~> 1.0’ # awesome.gem # awesome/lib/awesome.rb require ‘awesome/railtie’ if defined?(Rails)

Slide 26

Slide 26 text

How are Railties Discovered? class Railtie autoload :Configuration, "rails/railtie/configuration" include Initializable ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Engine Rails::Application) class << self private :new delegate :config, to: :instance def subclasses @subclasses ||= [] end def inherited(base) unless base.abstract_railtie? subclasses << base end end

Slide 27

Slide 27 text

How are Railties Discovered? class Railtie autoload :Configuration, "rails/railtie/configuration" include Initializable ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Engine Rails::Application) class << self private :new delegate :config, to: :instance def subclasses @subclasses ||= [] end def inherited(base) unless base.abstract_railtie? subclasses << base end end def subclasses @subclasses ||= [] end def inherited(base) unless base.abstract_railtie? subclasses << base end end

Slide 28

Slide 28 text

class Railtie The core API that all of Rails is built upon class ActionMailer::Railtie
 class ActionController::Railtie
 class ActionDispatch::Railtie
 ...
 class ActiveModel::Railtie
 class ActiveRecord::Railtie
 class ActiveSupport::Railtie If Rails can dogfood their own APIs to create Rails,
 chances are you can build awesome things too.

Slide 29

Slide 29 text

Extending with Railties class Engine < Railtie class Application < Engine class Plugin < Engine

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Full engines Overhauled Railties 2005 2011 Rails 3.1 2007 Rails 2.0 2009 Rails 2.3 2010 Rails 3.0 Engine concept introduced Mountable engines

Slide 32

Slide 32 text

Mountable Engines http://www.flickr.com/photos/granada_turnier/5818853700

Slide 33

Slide 33 text

Mountable Engine $ rails plugin new \
 name --mountable Like full engines, but... --Namespaced --Routes must be mounted in your app http://www.flickr.com/photos/tshearer/3935429228

Slide 34

Slide 34 text

Isolation via Namespacing

Slide 35

Slide 35 text

Full vs Mountable> Defining # defining full engines class Engine < ::Rails::Engine end

Slide 36

Slide 36 text

module Blog end # defining mountable engines isolate_namespace Blog class Engine < ::Rails::Engine end Full vs Mountable> Defining

Slide 37

Slide 37 text

Full vs Mountable> Application Controller # Mountable engines define their # own ApplicationController module Blog class ApplicationController < ActionController::Base end

Slide 38

Slide 38 text

Full vs Mountable> Routes # Full engine routes Rails.application.routes.draw do resources :posts end

Slide 39

Slide 39 text

Blog::Engine.routes.draw do resources :posts end Rails.application.routes.draw do mount Blog::Engine => ‘/blog’ end # Mountable engine routes Full vs Mountable> Routes

Slide 40

Slide 40 text

Full Mountable App ✔ ✔ Namespaced ✔ Routes Engines: Full vs Mountable Recap Inherited
 by your app Must be
 mounted

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

http://www.paleofuture.com/blog/2007/4/24/postcards-show-the-year-2000-circa-1900.html Full+Mountable Engine?

Slide 43

Slide 43 text

Full + Mountable Engine # Start with a mountable engine $ rails plugin new \ name --mountable

Slide 44

Slide 44 text

Full + Mountable Engine (cont) # Draw routes into the main app # like a full engine # Caution: Beware of collisions! Rails.application.routes.draw do resources :posts end

Slide 45

Slide 45 text

Mountable engines Full engines Overhauled Railties 2005 2012 Rails 3.2 2011 Rails 3.1 2007 Rails 2.0 2009 Rails 2.3 2010 Rails 3.0 Engine concept introduced vendor/plugins deprecated

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

Mountable engines Full engines Overhauled Railties vendor/plugins deprecated 2005 2012 Rails 3.2 2011 Rails 3.1 2013 Rails 4.0 2007 Rails 2.0 2009 Rails 2.3 2010 Rails 3.0 Engine concept introduced Plugin removed

Slide 48

Slide 48 text

git rm plugin.rb

Slide 49

Slide 49 text

git rm plugin.rb

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

Testing Engines http://www.flickr.com/photos/kwl/4809326028

Slide 53

Slide 53 text

Dummy App • Full and Mountable engines are tested the same • A full blown dummy app is generated in /test which consumes your engine • Write tests against the dummy app http://www.flickr.com/photos/20759665@N03/7400887540

Slide 54

Slide 54 text

$ gem install combustion http://www.flickr.com/photos/ekilby/4877912932

Slide 55

Slide 55 text

When do you create an Engine? http://www.flickr.com/photos/m0php/530526644

Slide 56

Slide 56 text

http://www.flickr.com/photos/limebye/3775235515 Start with a Monorail

Slide 57

Slide 57 text

http://www.flickr.com/photos/wwwuppertal/6891421635 Refactor out engines only when you find commonality and duplication

Slide 58

Slide 58 text

thank you. @kpshek