Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

The Rails Engine That Could - In Motion


Published on

Published in: Technology
  • Be the first to comment

The Rails Engine That Could - In Motion

  1. 1. Problem Difficulty reusing functionality cutting across: Models Views Controllers Assets (JS, CSS, Images) Duplication across all web application layers.
  2. 2. Courtesy of © 2002-2011 National Collegiate Scouting Association - All Rights Reserved
  3. 3. 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
  4. 4. Example Common Domain Rails Engine Search Map Rails Engine High School Public Athlete Recruiting Profiles Recruiting Rails App Rails App Rails App
  5. 5. Courtesy of © 2002-2011 National Collegiate Scouting Association - All Rights Reserved
  6. 6. Courtesy of © 2002-2011 National Collegiate Scouting Association - All Rights Reserved
  7. 7. Overview Engines let applications reuse: Models / Views / Controllers / Helpers Assets (JS, CSS, Images) Routes Rake tasks Initializers RSpec / Cucumber More (migrations, seeds, libraries)
  8. 8. 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)
  9. 9. lib/engine_name.rb
  10. 10. lib/engine_name/engine.rb
  11. 11. 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
  12. 12. Load Order Typically Rails app files load first before Engine files. Strongly recommended to reverse (by patching “active_support/dependencies.rb”) so that engine’s Ruby code is overrideable in app (see next slide) ERB files can be overridden in Rails app
  13. 13. Ruby Code Customization Model/Helper/Controller behavior can be customized be redefining .rb files in Rails app: Add new methods/behavior Replace existing methods Extend existing methods via alias_method_chain
  14. 14. View Customization View files (erb, haml, etc…) and Asset files (js, css, and images) can be redefined in Rails app to override completely for customization purposes
  15. 15. Code Examples
  16. 16. 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
  17. 17. Improved Productivity viaSymlinking Multiple engine dependencies can hamper productivity when frequently going back and forth between engines and app Engines gems installed via bundler can be symlinked to allow continuous development until done with both app and engine: more-productive-rails-engine.html
  18. 18. 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
  19. 19. Engines Reuse Engines Rails engines can reuse other Rails engines When multiple levels of depth are involved (e.g. App => Engine 1 => Engine 2), commit repos and update Gemfile from the bottom up (e.g. Engine 2 => Engine 1 => App)
  20. 20. Engine Configuration Engines can be configured to customize rack middleware, load paths, generators, and Rails component paths. More details at: ne.html
  21. 21. Isolated Engines To avoid Ruby namespace clash with Models/Helpers/Controllers, you can define an isolated namespaced engine:
  22. 22. 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
  23. 23. Pattern - Common Domain Problem: Multiple applications need to share a basic domain model but want to customize behavior without mixing concerns across apps Solution: In engine, please basic domain model definitions and common associations only In each app, define specialized behavior and extra associations for domain models
  24. 24. Pattern - Expose Helper Problem: need to customize presentation logic for a view in one app only, but keep the same logic in others Solution: In engine, extract helper logic that needs customization into its own helper. In app, redefine that new helper with customizations.
  25. 25. Pattern - Expose Partial Problem: need to customize a part of the view in one app only, but keep it the same in others Solution: In engine, extract view part that needs customization as a partial. In app, redefine that partial with customizations.
  26. 26. Pattern - Extension Partial Problem: One app needs to add content to a view that is not needed in other apps Solution: In engine, introduce a new partial with empty contents in area that needs extension for the one app. In app, define that partial with the required content.
  27. 27. Pattern - Extension Partial SIDEBAR Extension Partial Courtesy of © 2011 Groupon, Inc. All Rights Reserved.
  28. 28. Pattern - Extension Point Problem: different apps need to contribute data to a view in different places (e.g. contribute columns/rows in different spots) Solution: In engine, add logic that looks up partials in a specific ext directory, and based on file name (e.g. row_7.html.erb), determine index on where to insert it in the view. In app, define these partials with the right file names and locations.
  29. 29. Pattern - Extension Point12345
  30. 30. Pattern - ConfigurableFeatures Problem: different apps need different features from an engine in different combinations Solution: In engine, add logic that looks up configuration options from a constant hash (e.g. ENGINE_XYZ_CONFIG = {:header => “visible”, :footer => “visible”, …}). In app, configure engine by overriding configuration options (e.g. ENGINE_XYZ_CONFIG[:header] = “hidden”)
  31. 31. 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
  32. 32. 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)
  33. 33. More Info ne.html productive-rails-engine.html s-engines-extending- functionality/2990539#2990539
  34. 34. Contact Andy Maleh Code Painter Blog Twitter: @AndyMaleh