Routing rspec with nested routes

Problem

You would like to add a routing rspec test in your rails application that tests for a nested route.
So while you have something like the following in your config/routes.rb file:

namespace :admin do
  resources :users do
    resources :audits, only: [:index]
  end
end

you want to add the following test for your route:

expect(get: '/admin/users/:user_id/audits').to route_to(controller: 'admin/audits', action: 'index')

but you are getting an error like the following:

The recognized options <{"controller"=>"admin/audits", "action"=>"index", "user_id"=>":user_id"}> did not match <{"controller"=>"admin/audits", "action"=>"index"}>, difference:.
       --- expected
       +++ actual
       @@ -1 +1 @@
       -{"controller"=>"admin/audits", "action"=>"index"}
       +{"controller"=>"admin/audits", "action"=>"index", "user_id"=>":user_id"}

Solution

You will need to change your rspec to the following using any number for the user_id:

expect(get: '/admin/users/42/audits').to route_to(controller: 'admin/audits', action: 'index', user_id: '42')

Solution adapted from here

make the unpermitted parameters errors in Ruby on Rails more obvious

Problem

When you are adding new attributes to your model after the initial creation, they are not by default included in the permitted parameters list. Sometimes the error is not so obvious to see when testing, unless you look at the test log files.

Solution

To make the error more obvious, there is the following configuration option that you can set up in config/environments/test.rb (tip taken from Rails 4 In Action):

config.action_controller.action_on_unpermitted_parameters = :raise

Upgrading from rspec-rails 2.x to rspec-rails 3.x

Problem

You would like to upgrade your rails project from using rspec-rails 2.x to the latest rspec-rails 3.x version. According to the rspec-rails documentation the new 3.x includes many breaking changes.

Solution

The full instructions for upgrading from rspec-rails 2.x to rspec-rails 3.x are here, but you may not need to complete all the steps described in there.
So you could try with the following shorter steps:

  • Run your rspec tests and make sure that they all pass
  • Upgrade your rspec-rails to the version 2.99 provided by the rspec-rails team
  • Run your rspec tests again, and you should have deprecation warnings. Usually that would consist of:
    spec-rails 3 will no longer automatically infer an 
    example group's spec type from the file location. 
    You can explicitly opt-in to this feature using 
    this snippet:
    
    RSpec.configure do |config|
      config.infer_spec_type_from_file_location!
    end

    which you could add to your spec/spec_helper.rb file

  • Run your rspec tests again and this time they should have no deprecation warnings
  • If they all pass then upgrade to the latest rspec-rails (ie 3.0.1).
  • Run your rspec tests again, and this time you should normally have one deprecation warning:
    Requiring `rspec/autorun` when running RSpec via the `rspec` 
    command is deprecated. 
    Called from /xxx/xx/lib/active_support/dependencies.rb:247:
    in `require'.
  • Delete the line require ‘rspec/autorun’ from your spec/spec_helper.rb file
  • Rerun your tests and they should all be passing in rspec-rails 3.x now

SSL testing in rspec

Problem
You have added the force_ssl option in your rails application, and the rspec tests fail with a redirection as ssl is required in the test evnironment.

Solution
Using a solution provided here you can add the following to your rspec test to ensure that ssl is used and the tests pass:

before(:each) do
  request.env["rack.url_scheme"] = "https"
end

Replacing mock objects with factory girl in controller rspecs

Problem

You would like to use factory_girl instead of the mock models described in the RSpec book (Behaviour Driven Rails – Rails Controllers – Controller specs).

 

Solution

Make sure that you use let! instead of let and have the following:

 

require 'spec_helper'

describe MessagesController do
  describe "POST create" do
    let!(:message) { Factory.create(:message) }
    
    before do 
      Message.stub(:new).and_return(message)
    end
    
    it "creates a new message" do
      Messagee.should_receive(:new).with("text" => "a quick brown fox").and_return(message)
      post :create, :message => {"text" => "a quick brown fox"}
    end
    
    it "saves the message" do
      message.should_receive(:save)
      post :create
    end

    it "redirects to the Messages index" do
      post :create
      response.should redirect_to(:action => "index")
    end
  end
end

The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource. (Errno::ENOSPC)

Problem

When using the guard gem together with spork and cucumber and rspec to automate testing in your rails app, you get the following error:

The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource. (Errno::ENOSPC)

which also causes the guard to stop running.

Solution

Looking at the directory where the error takes place it appears there are a lot of temp files in the public/uploads/tmp directory that are not cleared up (using carrierwave for image uploading).
Maybe adding an initializer as suggested here would solve the clearing up of the files.
Otherwise by manually deleting the files and running guard again, it should work as expected.

Formatting edit field values in a Rails edit view

Problem
You have an edit form that displays a value in a format (ie dates) that you want to modify by using a helper method (ie display_datetime).

Solution
According to the suggestion here, you can use the following in your view:

<%= f.text_field :date_field_to_format, :value => display_datetime(f.object.date_field_to_format) %>

Testing associations in Rspec

Problem
You would like to test your model associations in an RSpec model spec, to make sure that they are correctly set up.

Solution
After some Google searching and coming across this article here, ended up using the second method described there with the reflect_on_association method, as it doesn’t need the inclusion of another gem.
So for example to to test multiple has_many or belongs_to associations in your model rspec you could use something like:
context "check associations" do
# belongs_to associations
%w{bel_to1 bel_to2}.each do |bt|
it "should belong to #{bt}" do
m = Model.reflect_on_association(:"#{bt}")
m.macro.should == :belongs_to
end
end
# has_many associations
%w{has_many1 has_many2 has_many3}.each do |hm|
it "should have many #{hm}" do
m = Model.reflect_on_association(:"#{hm}")
m.macro.should == :has_many
end
end
end

Couldn’t find ‘rspec’ generator – Rails 2.3.10

Problem
You are trying to use rspec with Ruby on Rails 2.3.10, but although you install the rspec and rspec-rails gems you get the following error when you try to run script/generate rspec
Couldn't find 'rspec' generator

Solution
It turns out that there is a problem with the versions used, so by following the instructions for Rails >= 2.3.10 from here, you should be able to install the plugins and use rspec:
ruby script/plugin install git://github.com/dchelimsky/rspec.git -r 'refs/tags/1.3.1'
ruby script/plugin install git://github.com/dchelimsky/rspec-rails.git -r 'refs/tags/1.3.3'
ruby script/generate rspec

where the last tag (1.3.3) should be the latest tag for each gem.

*** NOTE *** If you get an error like :
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map (NoMethodError)

uncomment the following line (line 11) from features/support/env.rb:
require 'cucumber/rails/rspec'
and run rake cucumber again.