Rails engines in
large apps
Created by /Enrico Teotti @agenteo
Start off with a small
application
and the app complexity will
grow over time
Start off with a big complex
application
ignoring complexity will hurt
you
In Ruby on Rails that is:
too many responsibilities in
active record models
long controller methods
helpers modules doing a
gazillion things
concerns
These poor decisions are sometime justified as:
"This is the Rails way!"
"Those are the Rails
conventions!"
"This is what ...
bullshit
Rails gives conventions that fit small application domains but doesn't
have any for larger problems
How can Ruby on Rails engines
help?
Engines can drop in functionality in your Rails monolithic app
Devise
Kaminari
But they can do more that that
"Rails::Engine allows you to wrap a specific Rails application or subset of
functionality a...
we will create very specific engine only used in this app
Domain Model
This is a domain model taken from Evan's book DDD
It is a simplified version of a real live problem
use Engines as building bricks
of the application!
First, create an integration test
in the main app
spec/features/ship_cargo_spec.rb
require 'spec_helper'
feature 'As a sta...
rspec
F
Failures:
1) As a staff member I want to ship a cargo
Given I am on the cargo shipping page
When I fill in a custo...
Create an engine
rails plugin new cargo_shipping --mountable -T --dummy-path=spec/dummy
You can create a nested folder
structure
If you want to be more formal about the separation of
responsibilities between th...
Main app Gemfile
gem 'cargo_shipping', path: 'engines/presentation_layer/cargo_shipping'
Cargo Shipping Engine
structure
engines/presentation_layer/cargo_shipping/
├── Gemfile
├── Gemfile.lock
├── MIT-LICENSE
├─...
CargoShipping Engine routes
engines/presentation_layer/cargo_shipping/config/routes.rb
module PresentationLayer
CargoShipp...
CargoShipping Engine
controller
engines/presentation_layer/cargo_shipping/app/controllers/cargo_shipping/ship_cargo_contro...
Run the test again!
F
Failures:
1) As a staff member I want to ship a cargo
Given I am on the cargo shipping page
When I f...
We need to change the main
app routes!
config/routes.rb
Maersk::Application.routes.draw do
mount CargoShipping::Engine, at...
rspec
.
Finished in 0.05205 seconds
1 example, 0 failures
CargoShipping Engine
engines/presentation_layer/cargo_shipping/app/controllers/cargo_shipping/ship_cargo_controller.rb
mod...
rspec
F
Failures:
1) As a staff member I want to ship a cargo
Given I am on the cargo shipping page
When I fill in a custo...
Create a domain layer engine
rails plugin new customers --mountable -T --dummy-path=spec/dummy
Main app Gemfile
gem 'cargo_shipping', path: 'engines/presentation_layer/cargo_shipping'
gem 'customers', path: 'engines/d...
Generating models in
Customers Engine
engines/domain_layer/customers/app/models/customers/customer_repository.rb
rails gen...
rspec
.
Finished in 0.05205 seconds
1 example, 0 failures
Mailing list:
https://groups.google.com/forum/?hl=en#!forum/components-in-rails
References:
Wrangling Large Rails Codebase...
THE END
Enrico Teotti / @agenteo / teotti.com
Rails engines in large apps
Rails engines in large apps
Rails engines in large apps
Rails engines in large apps
Upcoming SlideShare
Loading in …5
×

Rails engines in large apps

667
-1

Published on

Published in: Technology, Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
667
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
10
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Rails engines in large apps

  1. 1. Rails engines in large apps Created by /Enrico Teotti @agenteo
  2. 2. Start off with a small application
  3. 3. and the app complexity will grow over time
  4. 4. Start off with a big complex application
  5. 5. ignoring complexity will hurt you
  6. 6. In Ruby on Rails that is:
  7. 7. too many responsibilities in active record models
  8. 8. long controller methods
  9. 9. helpers modules doing a gazillion things
  10. 10. concerns
  11. 11. 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!"
  12. 12. bullshit
  13. 13. Rails gives conventions that fit small application domains but doesn't have any for larger problems
  14. 14. How can Ruby on Rails engines help?
  15. 15. Engines can drop in functionality in your Rails monolithic app Devise Kaminari
  16. 16. 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 larger packaged application. Since Rails 3.0, every Rails::Application is just an engine, which allows for simple feature and application sharing." Rails API
  17. 17. we will create very specific engine only used in this app
  18. 18. Domain Model This is a domain model taken from Evan's book DDD It is a simplified version of a real live problem
  19. 19. use Engines as building bricks of the application!
  20. 20. First, create an integration test in the main app spec/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' end end
  21. 21. rspec F Failures: 1) As a staff member I want to ship a cargo 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 Failure/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 seconds 1 example, 1 failure </top>
  22. 22. Create an engine rails plugin new cargo_shipping --mountable -T --dummy-path=spec/dummy
  23. 23. You can create a nested folder structure If you want to be more formal about the separation of responsibilities between the engines The engine name will match ubiquitous language you share with stakeholders engines/ ├── application_layer ├── domain_layer │ ├── billing │ ├── customer │ └── shipping └── presentation_layer └── cargo_shipping
  24. 24. Main app Gemfile gem 'cargo_shipping', path: 'engines/presentation_layer/cargo_shipping'
  25. 25. Cargo Shipping Engine structure 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
  26. 26. CargoShipping Engine routes engines/presentation_layer/cargo_shipping/config/routes.rb module PresentationLayer CargoShipping::Engine.routes.draw do get 'ship_cargo', to: 'ship_cargo#new' end end
  27. 27. CargoShipping Engine controller engines/presentation_layer/cargo_shipping/app/controllers/cargo_shipping/ship_cargo_controller.rb module CargoShipping class ShipCargoController < ActionController::Base def new end end end
  28. 28. Run the test again! F Failures: 1) As a staff member I want to ship a cargo 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 Failure/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 seconds 1 example, 1 failure </top>
  29. 29. We need to change the main app routes! config/routes.rb Maersk::Application.routes.draw do mount CargoShipping::Engine, at: "/" end
  30. 30. rspec . Finished in 0.05205 seconds 1 example, 0 failures
  31. 31. CargoShipping Engine engines/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 end end
  32. 32. rspec F Failures: 1) As a staff member I want to ship a cargo 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 Failure/Error: visit '/ship_cargo' NameError: uninitialized constant CargoShipping::ShipCargoController::Customers # ./engines/presentation_layer/cargo_shipping/app/controllers/cargo_shipping/ship_cargo_controller.r # ./spec/features/ship_cargo_spec.rb:10:in `block (2 levels) in <top (required)="">' Finished in 0.04333 seconds 1 example, 1 failure </top>
  33. 33. Create a domain layer engine rails plugin new customers --mountable -T --dummy-path=spec/dummy
  34. 34. Main app Gemfile gem 'cargo_shipping', path: 'engines/presentation_layer/cargo_shipping' gem 'customers', path: 'engines/domain_layer/customers'
  35. 35. Generating models in Customers Engine engines/domain_layer/customers/app/models/customers/customer_repository.rb rails generate model CustomerRepository email name invoke active_record create db/migrate/20130921154844_create_customers_customer_repositories.rb create app/models/customers/customer_repository.rb invoke rspec create spec/models/customers/customer_repository_spec.rb
  36. 36. rspec . Finished in 0.05205 seconds 1 example, 0 failures
  37. 37. Mailing list: https://groups.google.com/forum/?hl=en#!forum/components-in-rails References: Wrangling Large Rails Codebases Architecting 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/
  38. 38. THE END Enrico Teotti / @agenteo / teotti.com
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×