49

I'm doing an engine here, it works alright in stand alone.

When I transform it into a gem, and load it inside another application, I get a lot of undefined errors, coming from my engine gem's dependecies.

Here is the gemspec:

s.add_dependency('paperclip')
s.add_dependency('jquery-rails')
s.add_dependency('rails3-jquery-autocomplete')
s.add_dependency('remotipart')
s.add_dependency('cancan')

In the application, when I do a bundle install, it lists all these dependencies, but as i run the application I receive a lot of undefined methods errors (has_attachment from paperclip for example). It seems that the application doesn't load the engines dependencies. Is this the default behavior? Can I change it? Same thing happened with a plugin inside the engine.

If I insert by hand those gems, in the application Gemfile, all works...

Tiago
  • 2,808
  • 4
  • 31
  • 41
  • can you see these installed in Gemfile.lock in the app? Does your engine Gemfile use 'gemspec' below the source? If your app Gemfile.lock shows these dependencies installed then I believe they should be available in the app. If you haven't seen this post, check it out -> http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/ – johnmcaliley Mar 02 '11 at 13:16

7 Answers7

77

Include them in your gemfile and run bundle install. Then require them in your lib/<your_engine>/engine.rb file. Don't forget to require rubygems

  require 'rubygems'
  require 'paperclip'
  require 'jquery-rails'
  require 'rails3-jquery-autocomplete'
  require 'remotipart'
  require 'cancan'

Then in your host app (The app where you included your gem) run bundle install/ bundle update (bundle update did the trick for me) and then everything should work perfectly. You can also test this by starting the console in your host app and just type the module name e.g.

Loading development environment (Rails 3.0.3)
irb(main):001:0> Paperclip
=> Paperclip

Hope this helps

Daniël Zwijnenburg
  • 2,529
  • 2
  • 19
  • 27
  • 4
    The OP's intention is to *not* be required to add the dependencies in the Gemfile of the application using the engine. (I'm having the same issues with a plugin.) The gems all appear in Gemfile.lock but they're not loaded by Rails automatically, it seems. – davemyron May 25 '11 at 20:40
  • 1
    If the gems are installed then require them in your lib//engine.rb file. – Daniël Zwijnenburg May 26 '11 at 14:23
  • 4
    @orangechicken - I think (maybe wrong) it is your engine/plugins responsibility to require any dependencies. Which should also be included in the gemspec. I think the Gemfile is just for development purposes. – Kris Sep 28 '11 at 09:46
  • 2
    @Kris: yes, this seems to be my findings too. An engine is seen as a normal gem, and gems have to put their depedencies in a .gemspec file. – Marten Veldthuis Dec 12 '11 at 15:30
  • 3
    @DaniëlZwijnenburg, isn't it strange to require them for the second time? They are once declared as dependencies in Engins's `.gemspec` file. So they MUST be loaded into hosting app without any additional `require` command. But they aren't. – Green Jun 17 '13 at 10:38
  • This is not working for me in Rails 4, anything else Do I need to add ? – loganathan Apr 10 '14 at 11:43
  • This does work in in rains 4.2.0 as an engine, albeit with different set of gems. – Victor S Feb 25 '15 at 22:58
25

You can require them manually like Daniel posted, and you can also require them automatically. You need to add dependencies in 3 files:

  • yourengine.gemspec

    s.add_dependency "rails", '4.1.0'
    s.add_dependency "sqlite3"
    
  • Gemfile

    # Imports dependencies from yourengine.gemspec
    gemspec
    
  • lib/yourengine.rb

    # requires all dependencies
    Gem.loaded_specs['yourengine'].dependencies.each do |d|
     require d.name
    end
    
    require 'yourengine/engine'
    
    module Yourengine
    end
    

Update: It's a simplistic demonstration of how to require the dependencies. You should test it and filter unwanted items, for example: require d.name unless d.type == :development (thx @imsinu9)

carlosvini
  • 1,524
  • 18
  • 17
  • 3
    This is pretty neat. Unfortunately, some gems have different naming conventions and thus the `require d.name` will fail with a `LoadError` so you might have to do a bit of rescuing. – David van Geest Apr 20 '15 at 21:41
  • 1
    That last loop is going to load all your development dependencies, too. :( – John Hinnegan May 10 '16 at 23:57
  • 1
    I recommend `require d.name unless d.type == :development` to avoid loading development dependency. – imsinu9 Apr 29 '18 at 19:12
2

from paperclip's README :

For Non-Rails usage:

class ModuleName < ActiveRecord::Base
  include Paperclip::Glue
  ...
end

I had the same issue and that fixed it for me.

tali
  • 93
  • 8
2

You must add the gem file to both the .gemspec file, and your engine.rb file. In the .gemspec file it would be like: s.add_dependency "kaminari", "0.16.1"

In the engine.rb file at the top add: require "kaminari"

I think you also need to add the gem to the rails engine Gemfile and bundle install, but I'm not certain if you need it there.

yoyodunno
  • 519
  • 5
  • 17
0

At the time being (Rails 3.1 and above I think), you shouldn't have do declare any gems in the test/dummy/Gemfile anymore:

Quote from test/dummy/Gemfile (generated using rails plugin new my_engine --full):

Declare your gem's dependencies in simple_view_helpers.gemspec. Bundler will treat runtime dependencies like base dependencies, and development dependencies will be added by default to the :development group.

Declare any dependencies that are still in development here instead of in your gemspec. These might include edge Rails or gems from your path or Git. Remember to move these dependencies to your gemspec before releasing your gem to rubygems.org.

Joshua Muheim
  • 10,965
  • 6
  • 61
  • 127
0

You really shouldn't need them on the Gemsec, and they should be loaded. When you say "here is the gemspec", you are surrounding it with Gem::Specification.new do |s| or something to that effect, right?

chesterbr
  • 2,847
  • 3
  • 27
  • 26
0

You can include all gems for the environment with a simple bundler command:

Bundler.require(*Rails.groups)

You could add this to an config/initializer.

sbonami
  • 1,723
  • 16
  • 29