Rails Engine Patterns
Upcoming SlideShare
Loading in...5
×
 

Rails Engine Patterns

on

  • 18,328 views

This talk covers a successful utilization of Rails Engines to share features that cut across the layers of MVC in different Rails 3 projects. Rails Engines thus provide the best of both worlds: ...

This talk covers a successful utilization of Rails Engines to share features that cut across the layers of MVC in different Rails 3 projects. Rails Engines thus provide the best of both worlds: improved productivity by reusing MVC code (including assets like Javascript, CSS, and Images) and better flexibility by allowing different applications to customize behavior as needed without reliance on application-dependent conditionals. Rails Engine patterns will be provided to guide developers on how to leverage Rails Engines' reusability and flexibility without sacrificing maintainability.

Statistics

Views

Total Views
18,328
Views on SlideShare
14,736
Embed Views
3,592

Actions

Likes
29
Downloads
146
Comments
0

46 Embeds 3,592

http://andymaleh.blogspot.com 1696
http://andymaleh.blogspot.ca 388
http://andymaleh.blogspot.in 361
http://lanyrd.com 161
http://andymaleh.blogspot.co.uk 133
http://andymaleh.blogspot.de 115
http://andymaleh.blogspot.it 72
http://andymaleh.blogspot.fr 71
http://andymaleh.blogspot.com.br 60
http://andymaleh.blogspot.jp 48
http://andymaleh.blogspot.ru 43
http://andymaleh.blogspot.com.es 42
http://andymaleh.blogspot.com.au 37
http://andymaleh.blogspot.gr 30
http://andymaleh.blogspot.se 30
http://andymaleh.blogspot.nl 23
http://andymaleh.blogspot.no 20
http://andymaleh.blogspot.ro 18
http://andymaleh.blogspot.tw 17
http://andymaleh.blogspot.dk 16
http://andymaleh.blogspot.mx 16
http://andymaleh.blogspot.com.ar 16
http://lab-jp.tumblr.com 15
http://andymaleh.blogspot.co.il 14
https://meta.discourse.org 13
http://andymaleh.blogspot.pt 13
http://andymaleh.blogspot.co.nz 11
http://andymaleh.blogspot.be 11
http://andymaleh.blogspot.ie 10
http://andymaleh.blogspot.kr 10
http://andymaleh.blogspot.cz 9
http://andymaleh.blogspot.fi 9
http://andymaleh.blogspot.ch 9
http://andymaleh.blogspot.sg 9
https://twitter.com 8
http://discourse.patchbee.com 7
http://andymaleh.blogspot.hk 5
http://andymaleh.blogspot.hu 5
http://andymaleh.blogspot.co.at 5
http://andymaleh.blogspot.sk 5
http://translate.googleusercontent.com 4
https://si0.twimg.com 2
http://andymaleh.blogspot.ae 2
https://twimg0-a.akamaihd.net 1
http://feedly.com 1
http://www.hanrss.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Rails Engine Patterns Rails Engine Patterns Presentation Transcript

  • Problem Difficulty reusing functionality cutting across: Models Views Controllers Assets (JS, CSS, Images) Duplication across all web application layers.
  • Courtesy of © 2002-2011 National Collegiate Scouting Association - All Rights Reserved
  • Solution Break common behavior into Rails Engines Customize models/controllers/helpers in each project where needed by reopening classes Customize Rails views in each project as needed by overriding templates Link to Rails Engines in Gemfile via Git repo
  • Example Common Domain Rails Engine Search Map Rails Engine High School Public Athlete Recruiting Profiles Recruiting Rails App Rails App Rails App
  • Courtesy of © 2002-2011 National Collegiate Scouting Association - All Rights Reserved
  • Courtesy of © 2002-2011 National Collegiate Scouting Association - All Rights Reserved
  • What is a Rails Engine? Ruby Gem + MVC stack elements
  • What is a Rails Engine? Rails Engines let applications reuse: Models / Views / Controllers / Helpers Assets (JS, CSS, Images) Routes Rake tasks Generators
  • What is a Rails Engine? Rails Engines let applications reuse: Initializers RSpec / Cucumber Rack application with middleware stack Migrations and seed data Libraries
  • Engine Definition An engine structure is similar to a Rails app having app, config, lib, spec, features, etc… lib/engine_name.rb (read online instructions) lib/engine_name/engine.rb (read online instructions) To reuse engine, use “jeweler” gem to generate gemspec (read online instructions)
  • lib/engine_name.rb
  • lib/engine_name/engine.rb
  • Engine Consumption Reference engine via Gemfile as a Ruby gem or Git repo hosted gemified project:Courtesy of © 2002-2011 National Collegiate Scouting Association - All Rights Reserved
  • Load Order Typically Rails app files load first before Engine files. Strongly recommended to reverse so that engine’s code is customizable in app
  • Load Order Reversing load order can happen in one of two ways: Patching “active_support/dependencies.rb” in Rails 3.1- (see next slide) Adjusting railties_order in Rails 3.2+
  • Ruby Code Customization Model/Helper/Controller behavior can be customized be redefining .rb files in Rails App Customizations get mixed in with files in Engine This allows: Adding new methods/behavior Replacing existing methods Extending existing methods (alias_method_chain)
  • Ruby CodeCustomization Example
  • Ruby CodeCustomization Example
  • View and AssetCustomization Engine View and Asset presentation can be customized by redefining files in Rails App Customizations completely override files in Engine Examples of customizable View and Asset files: ERB/Haml JS CSS Images
  • ViewCustomization Example
  • ViewCustomization Example
  • Recommended EngineCode Management• Each Engine lives in own Repo independent of Rails App• Each Engine has its own Gem dependencies (Gemfile)• Engines preferably share the same Ruby version as Rails App
  • Typical DevelopmentProcess1. Make changes in engine, rake, and commit obtaining a new GIT ref2. Update Gemfile in app with new git ref, run “bundle install” (getting ride of symlink)3. Rake and commit changes in app.4. If more changes in engine are needed go back to step 1
  • Improved Productivity viaSymlinking Multiple engine dependencies can hamper productivity when frequently going back and forth between engines and app Engine gems installed via bundler can be symlinked to allow continuous development until done with both app and engine:http://andymaleh.blogspot.com/2011/09/ more-productive-rails-engine.html
  • Improved DevelopmentProcess1. Open Rails app and symlink all engines “rake engine:symlink[engine_name]”2. Work in app and engine until done WITHOUT running “bundle install”3. Rake and commit changes in engine obtaining a new git ref4. Update Gemfile in app with git ref, run “bundle install” (getting ride of symlink)5. Rake and commit changes in app
  • Engines Reuse Engines Rails engines can reuse other Rails engines Common Domain Rails Engine Search Map Rails Engine High School Public Athlete Recruiting Profiles Recruiting Rails App Rails App Rails App
  • Engines Reuse Engines When multiple levels of depth are involved, commit repos and update Gemfile from the bottom up Example: Engine 2 => Engine 1 => App 1. Commit in Engine 2 2. Update Gemfile in Engine 1 and commit 3. Update Gemfile in App and commit
  • Engine Configuration Engines can be configured to customize rack middleware, load paths, generators, and Rails component paths. More details at: http://edgeapi.rubyonrails.org/classes/Rails/Engi ne.html
  • Isolated Engines To avoid Ruby namespace clash with Models/Helpers/Controllers, you can define an isolated namespaced engine. For more details, go to http://edgeapi.rubyonrails.org/classes/Rails/Engi ne.html
  • Rails Engine Patterns Goals: Keep engine code agnostic of app customizations Prevent bi-directional coupling to simplify reasoning about code Avoid app dependent conditionals to improve code maintainability
  • Pattern - Common Domain Problem: Multiple Rails Apps need to share a basic domain model including default CRUD and presentation behavior Example: need to reuse address model and form entry behavior
  • Pattern - Common Domain Solution: In engine, include basic domain models (base behavior, common associations) with their views, CRUD controllers, and routes. In each app, define domain model specialized behavior, extra associations, and custom views Make sure routes are declared with Rails.application.routes.draw (not Rails App name)
  • Pattern - Common Domain Example: address.rb, addresses_controller.rb, address route, and _address.html.erb
  • Pattern - Expose Helper Problem: need to customize presentation logic for a view in one app only, but keep the same logic in others Example: One App needs to hide address1 and county for non- government users. Other Apps wants to keep the fields displayed. You might start by overriding view, but then realize it is duplicating many elements just to hide a couple fields.
  • Pattern - Expose Helper Solution: In Engine, extract helper logic that needs customization into its own helper. In App, redefine that new helper with customizations.
  • Pattern - Expose Helper(view in Engine)
  • Pattern - Expose Helper(trying to customize view in App)
  • Pattern - Expose Helper Remove custom view from App Use requires_extended_address? helper in Engine wherever the App used government_user? In Engine, define requires_extended_address? to return true In App, define requires_extended_address? to return government_user?
  • Pattern - Expose Helper(view + helper in Engine)
  • Pattern - Expose Partial Problem: need to have different customizations in one part of the view in multiple apps Example: Address form One App needs an extra neighborhood field Another App needs an extra region field
  • Pattern - Expose Partial Example App 1:
  • Pattern - Expose Partial Example App 2:
  • Pattern - Expose Partial Solution: In Engine, extract view part that needs customization as a partial. In App, redefine that partial with customizations.
  • Pattern - Expose Partial Example: Define _address_extra_fields partial with empty content in Engine Redefine _address_extra_fields in Apps needing extra fields
  • Pattern - Extension Point Problem: multiple Apps need to contribute data to a View in different places Example: multiple Apps need to add custom Rows in different spots of a List that comes from an Engine
  • Pattern - Extension Point Engine defines only 3 elements in a list (About Me, News and Noteworthy) 1 2 3
  • Pattern - Extension Point Solution: In Engine, add Helper logic that looks up partials in a specific ext directory, and based on file name (e.g. row_7.html.erb) insert into the right location in the View. In App, define these partials with the right file names and locations.
  • Pattern - Extension Point App 1 adds “nav_bar_list_ext/_row_1.html.erb” 1 2 3 4
  • Pattern - Extension Point App 2 adds “nav_bar_list_ext/_row_4.html.erb” 1 2 3 4
  • Pattern - ConfigurableFeatures Problem: different apps need different features from an engine in different combinations
  • Pattern - ConfigurableFeatures Solution: In Engine, add logic that looks up configuration options In App, configure Engine by overriding configuration options
  • Pattern - ConfigurableFeatures Example: Engine defines engine_config.yml enable_address_extensions: true enable_address_headers: true App overrides some options in engine_config.yml Engine uses config options to customize behavior using conditionals
  • Rails Engine Costs Overhead in establishing a new Rails Engine gem project Continuous switching between projects and engines to get work done Upgrade of ref numbers in Gemfile on every commit (minimized with symlinking)
  • Rails Engine Benefits Code reuse across all application layers Better maintainability due to: Independent project codebases Cleanly defined boundaries between projects and reusable components (engines) Project tests get smaller and run faster
  • Engines vs Services Engines are better when: Reusing small MVC features, especially domain independent (e.g. Search Map) Preferring to avoiding network and infrastructure overhead over establishing a service Wanting to quickly extract and reuse a feature
  • Engines vs Services Web Services are better when: Reusing larger MVC features that depend on domain data Need to consume feature in another programming language or outside the organization boundaries Need to scale up feature performance independently of the application (e.g. separate DB)
  • Engines vs Services To keep an easier to maintain Agile code base, start simple and then move incrementally towards a more complex architecture: Extract an MVC feature as an engine first Convert engine into a service when the need arises
  • Questions & Answers ???
  • Review Basics of Rails Engines Rails Engine Patterns Improved Productivity Tips Summary of Benefits and Trade-Offs
  • More Info http://edgeapi.rubyonrails.org/classes/Rails/Engi ne.html http://andymaleh.blogspot.com/2011/09/more- productive-rails-engine.html http://stackoverflow.com/questions/2964050/rail s-engines-extending- functionality/2990539#2990539
  • Contact Andy Maleh / Software Engineer / Groupon Email: amaleh {at} groupon {dot} com Code Painter Blog: http://andymaleh.blogspot.com Twitter: @AndyMaleh