rails engines in large apps

42
Rails engines in large apps Created by / Enrico Teotti @agenteo

Upload: agenteo

Post on 05-Dec-2014

661 views

Category:

Technology


1 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Rails engines in large apps

Rails engines inlarge apps

Created by / Enrico Teotti @agenteo

Page 2: Rails engines in large apps

Start off with a smallapplication

Page 3: Rails engines in large apps

and the app complexity willgrow over time

Page 4: Rails engines in large apps

Start off with a big complexapplication

Page 5: Rails engines in large apps

ignoring complexity will hurtyou

Page 6: Rails engines in large apps

In Ruby on Rails that is:

Page 7: Rails engines in large apps

too many responsibilities inactive record models

Page 8: Rails engines in large apps
Page 9: Rails engines in large apps

long controller methods

Page 10: Rails engines in large apps
Page 11: Rails engines in large apps

helpers modules doing agazillion things

Page 12: Rails engines in large apps
Page 13: Rails engines in large apps

concerns

Page 14: Rails engines in large apps
Page 15: Rails engines in large apps

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

bullshit

Page 17: Rails engines in large apps

Rails gives conventions that fit small application domains but doesn'thave any for larger problems

Page 18: Rails engines in large apps

How can Ruby on Rails engineshelp?

Page 19: Rails engines in large apps

Engines can drop in functionality in your Rails monolithic app

DeviseKaminari

Page 20: Rails engines in large apps

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

we will create very specific engine only used in this app

Page 22: Rails engines in large apps

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

use Engines as building bricksof the application!

Page 24: Rails engines in large apps

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

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

Create an enginerails plugin new cargo_shipping --mountable -T --dummy-path=spec/dummy

Page 27: Rails engines in large apps

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

Main app Gemfilegem 'cargo_shipping', path: 'engines/presentation_layer/cargo_shipping'

Page 29: Rails engines in large apps

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

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

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

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

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

rspec.

Finished in 0.05205 seconds1 example, 0 failures

Page 35: Rails engines in large apps

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

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

Create a domain layer enginerails plugin new customers --mountable -T --dummy-path=spec/dummy

Page 38: Rails engines in large apps

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

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

rspec.

Finished in 0.05205 seconds1 example, 0 failures

Page 41: Rails engines in large apps

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

THE ENDEnrico Teotti / @agenteo / teotti.com