Rails engines in large apps
-
Upload
agenteo -
Category
Technology
-
view
665 -
download
1
description
Transcript of Rails engines in large apps
![Page 1: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/1.jpg)
Rails engines inlarge apps
Created by / Enrico Teotti @agenteo
![Page 2: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/2.jpg)
Start off with a smallapplication
![Page 3: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/3.jpg)
and the app complexity willgrow over time
![Page 4: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/4.jpg)
Start off with a big complexapplication
![Page 5: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/5.jpg)
ignoring complexity will hurtyou
![Page 6: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/6.jpg)
In Ruby on Rails that is:
![Page 7: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/7.jpg)
too many responsibilities inactive record models
![Page 8: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/8.jpg)
![Page 9: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/9.jpg)
long controller methods
![Page 10: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/10.jpg)
![Page 11: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/11.jpg)
helpers modules doing agazillion things
![Page 12: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/12.jpg)
![Page 13: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/13.jpg)
concerns
![Page 14: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/14.jpg)
![Page 15: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/15.jpg)
These poor decisions are sometime justified as:
"This is the Rails way!""Those are the Rails
conventions!""This is what a Rails developer
expect to see!"
![Page 16: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/16.jpg)
bullshit
![Page 17: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/17.jpg)
Rails gives conventions that fit small application domains but doesn'thave any for larger problems
![Page 18: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/18.jpg)
How can Ruby on Rails engineshelp?
![Page 19: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/19.jpg)
Engines can drop in functionality in your Rails monolithic app
DeviseKaminari
![Page 20: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/20.jpg)
But they can do more that that"Rails::Engine allows you to wrap a specific Rails application or subset of
functionality and share it with other applications or within a largerpackaged application. Since Rails 3.0, every Rails::Application is just an
engine, which allows for simple feature and application sharing."
Rails API
![Page 21: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/21.jpg)
we will create very specific engine only used in this app
![Page 22: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/22.jpg)
Domain ModelThis is a domain model taken from Evan's book DDD
It is a simplified version of a real live problem
![Page 23: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/23.jpg)
use Engines as building bricksof the application!
![Page 24: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/24.jpg)
First, create an integration testin the main appspec/features/ship_cargo_spec.rb
require 'spec_helper'
feature 'As a staff member I want to ship a cargo' do scenario %{ Given I am on the cargo shipping page When I fill in a customer And I fill in a origin and destination Then I want to see an itinerary } do visit '/ship_cargo' endend
![Page 25: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/25.jpg)
rspecF
Failures:
1) As a staff member I want to ship a cargoGiven I am on the cargo shipping pageWhen I fill in a customerAnd I fill in a origin and destinationThen I want to see an itineraryFailure/Error: visit '/ship_cargo'ActionController::RoutingError:No route matches [GET] "/ship_cargo"# ./spec/features/ship_cargo_spec.rb:10:in ̀block (2 levels) in <top (required)="">'
Finished in 0.00523 seconds1 example, 1 failure </top>
![Page 26: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/26.jpg)
Create an enginerails plugin new cargo_shipping --mountable -T --dummy-path=spec/dummy
![Page 27: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/27.jpg)
You can create a nested folderstructure
If you want to be more formal about the separation ofresponsibilities between the engines
The engine name will match ubiquitous language you share withstakeholders
engines/├── application_layer├── domain_layer│ ├── billing│ ├── customer│ └── shipping└── presentation_layer └── cargo_shipping
![Page 28: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/28.jpg)
Main app Gemfilegem 'cargo_shipping', path: 'engines/presentation_layer/cargo_shipping'
![Page 29: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/29.jpg)
Cargo Shipping Enginestructure
engines/presentation_layer/cargo_shipping/├── Gemfile├── Gemfile.lock├── MIT-LICENSE├── README.rdoc├── Rakefile├── app│ ├── assets│ ├── controllers│ ├── helpers│ ├── mailers│ └── views├── cargo_shipping.gemspec├── config│ └── routes.rb├── lib│ ├── cargo_shipping│ ├── cargo_shipping.rb│ └── tasks└── spec └── dummy
![Page 30: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/30.jpg)
CargoShipping Engine routesengines/presentation_layer/cargo_shipping/config/routes.rbmodule PresentationLayer CargoShipping::Engine.routes.draw do get 'ship_cargo', to: 'ship_cargo#new' endend
![Page 31: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/31.jpg)
CargoShipping Enginecontroller
engines/presentation_layer/cargo_shipping/app/controllers/cargo_shipping/ship_cargo_controller.rb
module CargoShipping class ShipCargoController < ActionController::Base
def new end
endend
![Page 32: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/32.jpg)
Run the test again!F
Failures:
1) As a staff member I want to ship a cargoGiven I am on the cargo shipping pageWhen I fill in a customerAnd I fill in a origin and destinationThen I want to see an itineraryFailure/Error: visit '/ship_cargo'ActionController::RoutingError:No route matches [GET] "/ship_cargo"# ./spec/features/ship_cargo_spec.rb:10:in ̀block (2 levels) in <top (required)="">'
Finished in 0.00523 seconds1 example, 1 failure </top>
![Page 33: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/33.jpg)
We need to change the mainapp routes!
config/routes.rbMaersk::Application.routes.draw do mount CargoShipping::Engine, at: "/"end
![Page 34: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/34.jpg)
rspec.
Finished in 0.05205 seconds1 example, 0 failures
![Page 35: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/35.jpg)
CargoShipping Engineengines/presentation_layer/cargo_shipping/app/controllers/cargo_shipping/ship_cargo_controller.rb
module CargoShipping class ShipCargoController < ActionController::Base
def new @customers = Customers::CustomerRepository.all end
endend
![Page 36: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/36.jpg)
rspecF
Failures:
1) As a staff member I want to ship a cargoGiven I am on the cargo shipping pageWhen I fill in a customerAnd I fill in a origin and destinationThen I want to see an itineraryFailure/Error: visit '/ship_cargo'NameError:uninitialized constant CargoShipping::ShipCargoController::Customers# ./engines/presentation_layer/cargo_shipping/app/controllers/cargo_shipping/ship_cargo_controller.rb:5:in ̀new'# ./spec/features/ship_cargo_spec.rb:10:in ̀block (2 levels) in <top (required)="">'
Finished in 0.04333 seconds1 example, 1 failure </top>
![Page 37: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/37.jpg)
Create a domain layer enginerails plugin new customers --mountable -T --dummy-path=spec/dummy
![Page 38: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/38.jpg)
Main app Gemfilegem 'cargo_shipping', path: 'engines/presentation_layer/cargo_shipping'gem 'customers', path: 'engines/domain_layer/customers'
![Page 39: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/39.jpg)
Generating models inCustomers Engine
engines/domain_layer/customers/app/models/customers/customer_repository.rb
rails generate model CustomerRepository email nameinvoke active_recordcreate db/migrate/20130921154844_create_customers_customer_repositories.rbcreate app/models/customers/customer_repository.rbinvoke rspeccreate spec/models/customers/customer_repository_spec.rb
![Page 40: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/40.jpg)
rspec.
Finished in 0.05205 seconds1 example, 0 failures
![Page 41: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/41.jpg)
Mailing list:https://groups.google.com/forum/?hl=en#!forum/components-in-rails
References:Wrangling Large Rails CodebasesArchitecting your Rails app for success!http://pivotallabs.com/leave-your-migrations-in-your-rails-engines/http://pivotallabs.com/experience-report-engine-usage-that-didn-t-work/
![Page 42: Rails engines in large apps](https://reader033.fdocuments.us/reader033/viewer/2022051323/5482a25fb079593d0c8b484b/html5/thumbnails/42.jpg)
THE ENDEnrico Teotti / @agenteo / teotti.com