Creating a rails 3 engine / plugin / gem

Keith Schacht| September 12th, 2010
Post to Twitter

One of the things I was most looking forward to in rails 3 was the plugin / engine architecture. Recently, I sat down to figure out how to create my first engine and package it up as a gem and it took me awhile of time just to get the structure of the engine setup. It’s missing a lot of the “rails” you get in a normal rails app.

In it’s simplest form engines are quite easy, however for a full-featured engine (such as creating a forum) there are a lot of extras that you’re going to want. These are the things I spent time figuring out that I’ve packaged up into an easy starting point:

  • Namespacing models & controllers so they don’t collide with those in the main app
  • Creating a global layout within your engine that gets nested within your application layout
  • Generating migrations from your engine
  • Creating an “acts_as_[plugin]” declaration for use inside your main app’s models
  • Easy plugin configuration file editable from main app directory
  • Rake tasks within engine
  • Writing tests for models complete with fixtures
  • Serving static assets within engine
  • Packaging and distributing as a gem

Code is here – I’ve created an engine stub that has all the things setup for you already. I want to see a lot more rails 3 engines get created, I hope this helps! I’d love to hear feedback from you if you try it out.

Here’s how you get ready to create your first gem by using this starting point:

  • git clone
  • cd rails_3_engine_demo
  • [edit test/database.yml]
  • rake test (this will initialize your test database and run the basic test suite)

Now, create a plain rails app and set it up to use your engine. FYI: even though the engine’s directory is ‘rails_3_engine_demo’, internally the engine is named ‘cheese’

  • cd .. [ this is to take you outside the 'rails_3_engine_demo' directory that was created above' ]
  • rails new demo_app_to_use_gem -d mysql
  • cd demo_app_to_use_gem
  • [edit config/database.yml]
  • [edit Gemfile, add line: ] gem ‘cheese’, :path => “../rails_3_engine_demo”
  • rails generate cheese
  • [examine config/initializers/cheese.rb to see basic config parameters]
  • rake db:create
  • rake db:migrate (one of the migrations that you’ll see run came from the engine)

You have now setup a empty rails app that utilizes your engine. To test out the functionality, startup the demo app’s webserver:

  • rails server
  • Then visit: http://localhost:3000/cheese (this is a controller included within the engine)
  • rake cheese:report (this is a a rake task that is included inside the engine)

Lastly, let’s package up your engine as a real gem. You’ll need Jeweler installed for this:

  • cd rails_3_engine_demo
  • sudo gem install jeweler
  • rake gemspec
  • rake build
  • rake install (you have now installed your engine as a gem locally)
  • [ At this point if you wanted your demo app to use your installed gem, edit the Gemfile in your demo app and remove the 'path' option from your gem line. It should look like this: ] gem ‘cheese’
  • rake gemcutter:release (this pushes your gem up to Gemcutter, a public gem repository)

Now you’re ready to start customizing this engine for your own purposes. Do a global find in your engine directory and replace every instance of “cheese” and “Cheese” with your engine name (be sure to preserve capitalization). Likewise, rename every directory and file that’s named “cheese” with your engine name. I should really automate this but I haven’t figured out how to create a rake task that I can run from within the engine directory itself.

BTW, the following resources were helpful in figuring all this out:

The Modest Rubyist, Jon Swope, Rails Dispatch

32 Responses to “Creating a rails 3 engine / plugin / gem”

  1. Rodrigo Dellacqua Says:
    September 22nd, 2010 at 2:13 pm

    You got a typo there,

    rails (new) demo_app_to_use_gem -D mysql

  2. Frank Says:
    September 27th, 2010 at 9:06 am

    Hi, when I run in production mode the static assets aren’t served properly. The files a empty. Have you experienced the same problem? Do you have a solution?

  3. Boris Says:
    September 29th, 2010 at 6:37 am

    Thanks for the post, just what I was looking for!

    I had a few problems though. For one, I couldn’t run the tests with “rake test” – I always get:

    no such file to load — app/models/cheese/widget.rb (LoadError)

    …even though the path seems to be correct – not sure what’s wrong here. Also using

    gem ‘cheese’, :path => “../cheese”

    didn’t work since there is no directory cheese, I had to use:

    gem ‘cheese’, :path => “../”

  4. Keith Schacht Says:
    September 29th, 2010 at 9:00 pm

    @Rodrigo: I fixed the typo, thanks for catching

    @Boris: Sorry, I had another typo. It should be: gem ‘cheese’, :path => ‘../rails_3_engine_demo’

    Basically, the demo rails app needs to point to the root directory where you have your engine.

    @Frank: Does it work locally when your Gemfile points to the directory? Does it work locally when your Gemfile refers to your locally installed gem?

    I did have that issue at one time too. My issue was that it worked when my Gemspec pointing to my local directory, but it failed once it’s compiled into an actual gem (both locally and in production). My solution was in the engine’s Rakefile, I added this line:

    gem.files = Dir["{lib}/**/*", "{app}/**/*", "{public}/**/*", "{config}/**/*"]

    Notice the “public” in there, this makes sure that the gem includes the public directory.

    However, all this should already be included in my demo above so maybe you’ve encountered a new issue. I haven’t been able to duplicate though.

  5. dave Says:
    October 1st, 2010 at 9:42 am

    Thanks! Spent a few hours hunting down a clear presentation on creating Rails 3 engines. Just what I needed!

  6. Ben Says:
    October 6th, 2010 at 12:42 pm

    Thanks a lot for your work!

  7. Yuriy Says:
    October 8th, 2010 at 12:42 pm

    Good job Keith!

    But you have mistake here:

    # rails db:create
    # rails db:migrate (one of the migrations that you’ll see run came from the engine)

    should be:
    # rake db:create
    # rake db:migrate (one of the migrations that you’ll see run came from the engine)


  8. Keith Schacht Says:
    October 8th, 2010 at 4:07 pm

    Ah, thanks for catching that, I just fixed it above.

  9. Andy Pearson Says:
    November 17th, 2010 at 2:40 am

    First off – thanks for releasing this! I’ve been putting together a gem of a custom CMS and this has been my one stop for finding out how to put things together.

    One thing I’m coming up against – is there anyway to extend the functionality of the host apps ApplicationController? I’ve tired a few different things but nothing seems to work. Thinking that would be a great thing to add to this demo!

    Thanks again!

  10. Keith Schacht Says:
    November 19th, 2010 at 11:48 am

    Andy, good question! I actually haven’t figured that out yet. I should look into that. I did include a way to create Application Helpers within the engine, maybe that would work for your purposes?

    If you figure out the Application Controller, can you fork my code and ping me with the commit? I’d love to pull that back in for other people.

  11. Mike Mondragon Says:
    December 15th, 2010 at 4:04 pm

    Awesome write up on Engines, I will definitely use your experience on an upcoming project. Here’s the clone command for the public:

    git clone

    Also, the version I checked out didn’t have a plural cheese report, just singular

    rake cheese:report

  12. Keith Schacht Says:
    December 23rd, 2010 at 10:27 am

    Thanks Mike, I just corrected those two typos.

  13. Joel Dezenzio Says:
    December 29th, 2010 at 7:21 am

    Hi Keith, you might want to update the test_helper.rb file to account for port configurations with mysql as some people use separate ports when developing. I’ve modified the test_helper.rb file to fix the path to widget.rb (someone above complained about receiving an error so this will fix it so that all OS environments find the right path). See the gist below:

  14. Joel Dezenzio Says:
    December 29th, 2010 at 7:34 am

    Hi Keith, also, how are you handling engines that will require gems or plugins? For instance, I’m planning on converting a forum software (which is very deeply coded) to an engine and I believe that any gems/plugin requirements should be maintained in the engine since they are essentially separate from the application. Thoughts?

  15. Joel Dezenzio Says:
    December 29th, 2010 at 8:02 am

    Hi Keith, third post of the day for me!

    I corrected your engine routing as the map is deprecated in rails 3.1 upcoming and so is name_prefix. See the gist for the corrected version.

  16. Joel Dezenzio Says:
    December 29th, 2010 at 11:14 am

    I corrected my gist above to also include scope as path_prefix does not work when used with resources. To make things easier, you should probably surround all of the resources you want to use with one dry scope…

    scope mount_at do

    .. your resources
    .. more resources


  17. Joel Dezenzio Says:
    December 29th, 2010 at 11:38 am

    I created a gist that shows a full fledged example of rails 3.0.3 routing from the inside and out using your rails engine.

    By the way, I really like your engine. It’s fairly adaptable. Nice job!

  18. choonkeat Says:
    January 23rd, 2011 at 7:52 pm

    should checkout too, it converts rails3 app into an engine

  19. Raoul Says:
    January 26th, 2011 at 7:47 am

    If I would have my models in a different directory than app; how should I configure the configuration files ?

    Suppose I have the models under lib in a directory structure A/B/C/x.rb where x is the model and the rest of the configuration, controllers, views reside under app.


  20. erwin Says:
    February 15th, 2011 at 3:22 am

    Thanks for this tuts … As Rails 3.1 coming .. I needed to work on some engine building now…

    Some point I did not get right … what should be written in the demo_app routes to know about the engine routes…

    running rake routes, I don’ get any cheese/widgets route at all…. I surely missed an important point .. but which one ?

  21. kie Says:
    November 27th, 2011 at 3:52 am

    small correction in the genator when the tree is not typical:

    tmp_real_path = File.expand_path(“tmp/~application.html.erb”)

    tmp = tmp_real_path, “w”
    tmp.write layout; tmp.close

    remove_file ‘app/views/layouts/application.html.erb’
    copy_file tmp_real_path, ‘app/views/layouts/application.html.erb’
    remove_file tmp_real_path

  22. Nicholas Hughes Says:
    January 31st, 2012 at 5:29 pm

    @Frank (or for anyone else who stumbles across this):

    Mounting a Rails 3.1 engine (with assets at /app/assets) on our 3.1 app (expecting assets at root/public) required adding the following to our engine’s engine.rb file to serve assets in staging/production:

    initializer “static assets” do |app|
    app.middleware.insert_before ::Rack::Lock, ::ActionDispatch::Static, “#{root}/app/assets”

    It seems to me that there is probably a more elegant way to present the mounted engine’s static assets to its host application, but my work today didn’t yield any insight.

    I hope this helps someone!

  23. Renaud Says:
    February 16th, 2012 at 1:46 am

    thanks for this tuto.

    My first engine was a pure success, but I decided to make one more and the second one override the first one:
    I lost roots of my first engine, if i debug I can see the Engine.config.mount_at is replaced by the second one, even if my second engine is not in the same namespace or has a different name.

    thank you for helping me

  24. Rails Mountable Engine Creation, installation, unistallation | Learning with Earning Says:
    September 25th, 2013 at 8:20 am

    [...] Engine Points [...]

  25. tinnitus solutions Says:
    August 24th, 2014 at 9:22 pm

    This is a topi that’s near to my heart… Best wishes!
    Exzctly where are your contact details though?

    my webpage … tinnitus solutions

  26. Anneliese Says:
    January 31st, 2015 at 3:30 am

    I do not even understand how I ended up here, but
    I thought this submit was once good. I don’t realize who you are however definitely you are going to
    a well-known blogger when you are not already. Cheers!

  27. Zelda Says:
    February 16th, 2015 at 5:00 pm

    I spend time effectively and I develop myself, not my game character.
    These typess of Android apps start opportunities for business services.

    There iss actually just one spy program for phones that does lett you install to annd monitor an infinite number of
    phones called spybubble at.

  28. Jose Says:
    April 8th, 2015 at 3:44 pm

    The best part about these games is thhe fact that yoou don’thave to
    leave your home or as much as your couch to play them with
    your child. The phone’s vide recording capability is via QVGA and at 15 frames per second (fps).
    Below is a list of ideas and suggestions that will helop ALL students to succeed
    in the SMET classroom.

  29. Brigette Says:
    April 9th, 2015 at 10:24 pm

    Designing and building a mobile website are two
    different things. One off many text-editing tools forr i –
    OS, Hog Bay Software’s Plain – Text is my current favorite, mostly because iit syncs
    documents directly to Droplbox (the file sync software I’ve
    mentioned numerous times). IPads are also very user-friendly, and simple
    to handle.

  30. Nutrition Says:
    April 13th, 2015 at 8:06 pm

    Awesome post.

  31. travel Says:
    April 14th, 2015 at 12:12 am

    When you’re ready, head down to the town square to mingle amongst your citizens.
    Lucy and Ricky’s best friends are landlords Fred and
    Ethel Mertz who often become intertwined in Lucy’s get-rich-quick schemes, screwball ideas,
    and comic shenanigans. Problem is, most families with kids travel to Disneyland at the same time of year – the summer months.

  32. cases for the iphone 6 plus Says:
    June 25th, 2015 at 10:22 am

    I visited ?arious web ?ages howe?er the audio quality f?r audio songs existing ?t thi? site is genuinely

Leave a Comment