Rails Engines: Where to define gems only used in testing - ruby-on-rails

I'm building an engine, and I want to use VCR and Webmock for testing.
The documentation within the Gemfile generated when an engine is created, seems to suggest that all an engine's gems should be loaded via gemspec, but the only options for this are add_dependency and add_development_dependency. If I use the latter, VCR and Webmock get loaded into my development environment, and I then have to explicitly disable Webmock in the development environment. I'd rather not do that as a host app may want these gems to work in development, and my engine disabling them may be unexpected.
The obvious solution would appear to be to use the engine's Gemfile:
group :test do
gem 'vcr'
gem 'webmock'
end
Is this the right way to load gems that are only used when testing an engine?
Are there any gotchas doing this?

One of the well known rails engines, rails_admin (https://github.com/sferik/rails_admin) uses that approach, so I believe it can be considered a good practice.

What's the load order for Rails app and Rails app's Rails Engines?
My guess is that the Rails app Gemfile is the determining factor for a gem being loaded or not loaded. This might be worth a try in a Rails test app.

I believe the answer is that there is nothing wrong with declaring in an engine's Gemfile, gems only used for testing and debugging the engine code. Further, I think the Gemfile template should be made less ambiguous, and have submitted a pull request to this effect:
https://github.com/rails/rails/pull/11881

Related

Conditionally require gems in Gemfile based on Rails or Sinatra framework?

I am writing a gem that can be used with both Sinatra and Rails, however, the gem dependencies are different based on which framework the developer is using the gem on.
If it's a rails app, we need 'sass-rails' and 'coffee-rails'
If it's a sinatra app, we need 'sass' and 'coffee-script'
Ideally bundler would just install the necessary gems based on which framework this gem is being loaded into, but I can't seem to figure out how to conditionally specify dependencies.
Any suggestions would be much appreciated.
I would suggest you not to do that. It would be hackish and unreliable.
What you can do however is divide and conquer! Build a generic version of your gem that is framework agnostic and only handles the logic, let's call it yourgem-core, then you can build two other gems based on that first one, called yourgem-rails and yourgems-sinatra.
It's much better, only logic and logic test in yourgem-core, only rails integration tests in yourgem-rails, only sinatra integration tests in yourgem-sinatra
You can use :group option in bundler.
Reference: http://bundler.io/v1.5/groups.html

How to get other Gem helpers into my Engine Gem's tests?

I'm trying to write tests for an engine gem I'm writing. I'm using Rspec and the tests seem to be running fine. But whenever a view uses a helper from another gem, such as "will_paginate" or "ransack", I get an "undefined method" error.
I've tried including the other gems in my gem's Gemfile (in addition to the engine.gemspec file) as well as the dummy app's Gemfile, but I get the same error. I've also tried including the gems in the spec/spec_helper.rb file.
So I've tried most of the things mentioned here:
Setup RSpec to test a gem (not Rails)
Usually, for Rspec tests for a regular Rails app, these helpers seem to be just included some how since I don't have this issue running tests for a regular Rails app.
I also have been needing to namespace my url helpers in the views with something like:
engine.resources_path
I'm not sure if that's a symptom of some configuration I've messed up on.
Everything in the engine runs fine when mounted to another app and viewed on the browser.
Any ideas?
Turns out a better approach is to stub out methods from gems since the gem should be testing their own methods anyways. Please let me know if I'm misunderstanding anything. Thanks!

How do Ruby Gems Load in Rails?

Say I have a ruby gem that I want to use, but it's use is only needed in one model or controller.
Is there a way to load that gem exclusively for that one model or controller?
Would it be a waste of resources for it to be available systemwide (callable from any controller)
The answer posted is incorrect, it's perfectly possible to only load a gem for a particular model or controller. Your Gemfile allows you to define groups that Bundler can use to require certain gems. By default, any ungrouped gems along with the gems for the environment you are currently running in are required, and any named groups are not required. So if you had the following Gemfile:
gem 'always_used_gem', '1.0.0'
group :rarely_used do
gem 'rarely_used_gem', '1.0.0'
end
Then rarely_used_gem would not be required on initial application load. If you had a particular method that needed that functionality, you could do this:
def do_stuff
Bundler.require :rarely_used
# use stuff from rarely_used_gem
end
One note: make sure the Bundler.require is inside a method call or something like that, or else the group will be required when the file is parsed (i.e. application boot)
In terms of whether you want to do this, it should really only be used for exceptional circumstances. You're trading boot speed for execution speed by doing this, which might make sense in development but probably doesn't in production. Also, you can use this method if you have some incompatibilities between two gems (we use this to resolve issues between a couple of AWS gems, for instance.)
No, it's not possible. Once a gem has been loaded it will be available for all controllers / models / everything. This should not be a primary concern for you. RAM and CPU time is cheap, programmer's time is not.
Bundler autoloads/-requires all gems, unless
#Gemfile
gem :somegem, :require => false
Then you can do require it when you need it
#some_ruby_file.rb
#within_some_context
require 'somegem'
How useful it is and when to do this (except for when the load order is important, as for the mocha gem (needed to be loaded last)), I don't know. I leave this to your own judgement.

Problem creating Rails 3 Engine

I'm working on creating my first Rails 3 engine and I'm currently getting the following error message
is a Railtie/Engine and cannot be installed as plugin (RuntimeError)
To give you a bit more background I'm not doing the Engine as a gem, but I've place the Engine files in the vendor/plugins folder. I know there is an issue with loading when in the plugins folder, but I'm not clear on how to solve the problem.
My rails/init.rb file in the Engine has the following code
require 'rails'
module RailsApp
module MyEngine
class Engine < Rails::Engine
config.after_initialize do
RailsApp::GameType.register do |game_type|
game_type.name = "TreasureIsland"
game_type.version = "0.1"
game_type.thumbnail = "teasure_island.jpg"
end
end
end
end
end
Suggestions?
I think I remember reading that Railties would not work in plugins directory, because they are intended to be loaded at a different point in the application boot process. I would recommend creating a gem using something like Jeweler, which does alot of the work for you. The purpose of the Railtie/Engine is to have a reusable component that can be included in multiple rails apps. Once you have a gem created, you can point to the local gem path within your Gemfile. This allows you to see changes in your engine code inside your rails app without having to build and reinstall the gem every time you make a change to the engine code. Of course you would want to point bundler to the installed gem in production. I would recommend putting it on github and using that URL in your Gemfile in production.
Bundler local gem example:
#Gemfile
gem "my_engine", :require => "my_engine", :path => "/my_engines/my_engine"
Check out the Modern Rubyist's website. He has a good series on creating Railties and Engines. There may have been some changes to Rails since this was written, but I think most of it is still relevant. It helped me out a good bit when I was learning how to write Engines with Rails 3.
http://www.themodestrubyist.com/2010/03/01/rails-3-plugins---part-1---the-big-picture/
http://www.themodestrubyist.com/2010/03/05/rails-3-plugins---part-2---writing-an-engine/
http://www.themodestrubyist.com/2010/03/16/rails-3-plugins---part-3---rake-tasks-generators-initializers-oh-my/
http://www.themodestrubyist.com/2010/03/22/rails-3-plugins---part-4---more-on-generators/
John, I believe engines (which are typically gems) vs plugins (which live in vendor) are loaded at different points in the rails initialization process.
Engines actually have a bit more flexibility, they can hook deeper into rails. In addition, packaging as a gem has a lot of advantages: easier to share across apps, easier to maintain in a separate code repo, easier version control.
I'm creating my first rails engine right now and created a useful starting point and walk-through for getting started:
http://keithschacht.com/creating-a-rails-3-engine-plugin-gem/

Necessary steps for using a gem (e.g. json) in Ruby on Rails app?

I'm having trouble getting rubygems to work in my Rails app. Specifically, I'm trying to use the json gem, documented here: http://flori.github.com/json/ I can successfully use JSON.parse() in IRB and script/console but not in my rails app.
I know it's some combination of config.gem 'json' in environment.rb and other things, but can't find a good explanation anywhere.
Can someone give me a concise list of what is required to use this gem OR point me towards comprehensive documentation of using gems in Rails? thanks!
config.gem is used for gem dependency in rails and it does nothing more than telling rails that a gem is needed, and helping the user install the appropriate gem, etc (more details here: http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies)
however by installing a gem, it should be able to be used by the rails app automatically, if not, probably you can add require "json" into environment.rb or in an .rb files in the initializers folder?
Hope it helps =)
I solved it. There's decent documentation here: http://apidock.com/rails/Rails/Configuration/gem
Once you have used config.gem in environment.rb, you should not need to 'require' it later.
My problem was that I had not stopped and restarted the server! It worked in script/console because everything was getting reloaded every time.

Resources