#[1]gnikyt feed [2]gnikyt Code ramblings. Extending a Rails Engine /* Feb 20, 2016 — 4.3KB */ Redesigning my CMS in Rails has been great fun. There have been many challenges faced, and many conquered (like having 100% code coverage :D). One thought that crossed my mind after building the monster was how do you extend an engine? By extending, I mean to add or overwrite methods of controllers, models, helpers, etc. The [3]Rails Engine Guide is excellent and it has two main points on extending the engine functionality. One is by use of “decorators” and the other is by abstracting all your controller and model code into concerns inside your engine. While I like the concern method, as it gives more flexibility for complex extensions, its overkill in my opinion. The [4]decorator option is very easy to implement without changing much of your existing engine. The first step as the Rails guide shows you, is to add support for decorator loading inside your engine lib. Below is how I did it in my CMS engine called Guts: # lib/guts/engine.rb # ... etc ... isolate_namespace Guts config.to_prepare do Dir.glob("#{Rails.root}app/decorators/*/guts/*_decorator*.rb").each do |c| require_dependency c end end # ... etc ... This will look for all decorators in the main Rails apps for the path app/decorators/{controllers,models,concerns,helpers,etc}/guts/{file}_de corator(s).rb and load them in using [5]require_dependency. Now the engine has support to load the decorators, lets move on to some examples. All following examples from here-on-out will be using my engine for example purposes. Controllers Create a file in app/decorators/controllers/guts/ such as type_decorator.rb Add in the following code using class_eval from Ruby: Guts::TypesController.class_eval do # Decorator action is explode.. we will route this as: guts/types#explode def explode # Will render app/views/guts/types/explode.html.erb end end Next open app/config/routes.rb in your main Ruby app and prepend this new route at the very top of the route file before mounting the Guts engine in the Rails.application.routes.draw block. As an example: Guts::Engine.routes.prepend do # Create a route of /guts/types/explode # Map it to types controller and the explode method # Give the route a name of guts_types_explode get "/types/explode", to: "types#explode", as: :guts_types_explode end Rails.application.routes.draw do # Mount the Guts engine mount Guts::Engine => "/guts" end This will now prepend our new route to the engine and map /guts/types/explode to our decorator action. Lastly, create a view in app/views/guts/types/ called explode.html.erb with whatever you wish to display! This is the basics of extending a controller. Models As in controllers, create a file in app/decorators/models/guts/ such as type_modal_decorator.rb Add in the following code using class_eval from Ruby: Guts::Type.class_eval do # Override title setter def title=(title) self[:title] = "Tricked ya! New Title!" end # Adds a new method to the model def title_with_bang "#{self[:title]}!" end end Views As stated above for the controller example, since Rails looks in the main app for views first, you simply need to match the correct path. If your engine’s view for CoolController#jumps is app/views/{engine}/cool/jumps.html.erb you will duplicate this in your main Rails apps by creating a file in app/views/{engine}/cool/jumps.html.erb. You can then enter anything you need into that view and will be overridden. A good tip I used in my CMS engine was to utilize [6]yields. I placed named yields in many parts of my engine views so they can be utilized by a Rails app by calling [7]content_for in their views. Although the Rails Guide covers all this, I thought seeing a real-world example would help. Happy coding! [8]MD | [9]TXT | [10]CC-4.0 This post is 9 years old and may contain outdated information. __________________________________________________________________ [11]Ty King Ty King A self-taught, seasoned, and versatile developer from Newfoundland. Crafting innovative solutions with care and expertise. See more [12]about me. [13]Github [14]LinkedIn [15]CV [16]RSS * * * * * * * * * * References Visible links: 1. /rss.xml 2. / 3. http://edgeguides.rubyonrails.org/engines.html#improving-engine-functionality 4. http://edgeguides.rubyonrails.org/engines.html#overriding-models-and-controllers 5. http://apidock.com/rails/ActiveSupport/Dependencies/Loadable/require_dependency 6. http://guides.rubyonrails.org/layouts_and_rendering.html#understanding-yield 7. http://guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method 8. /extending-a-rails-engine/index.md 9. /extending-a-rails-engine/index.txt 10. https://creativecommons.org/licenses/by/4.0/ 11. /about 12. /about 13. https://github.com/gnikyt 14. https://linkedin.com/in/gnikyt 15. /assets/files/cv.pdf 16. /rss.xml Hidden links: 18. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-1 19. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-2 20. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-3 21. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-4 22. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-5 23. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-6 24. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-7 25. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-8 26. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-9 27. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb1-10 28. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb2-1 29. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb2-2 30. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb2-3 31. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb2-4 32. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb2-5 33. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb2-6 34. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-1 35. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-2 36. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-3 37. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-4 38. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-5 39. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-6 40. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-7 41. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-8 42. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-9 43. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-10 44. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb3-11 45. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-1 46. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-2 47. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-3 48. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-4 49. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-5 50. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-6 51. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-7 52. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-8 53. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-9 54. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-10 55. localhost/tmp/lynxXXXXFH0iSG/L769034-2001TMP.html#cb4-11