View spec with nested resource gives “No route matches”
When using will paginate on a view that includes a nested resource it breaks my view specs.
The view however works fine when visited by browser or feature specs.
It seems that the parent resource (station) is not included when calling url_for. I have been able to isolate it by doing:
before :each { view.stub(:url_for) }
The RSpec error message
2) stations/measures
Failure/Error: render
ActionView::Template::Error:
No route matches {:page=>2, :controller=>"stations", :action=>"measures"}
require 'spec_helper'
describe "stations/measures" do
let!(:station) { build_stubbed(:station) }
let!(:measures) do
# page, per_page, total_entries
WillPaginate::Collection.create(1, 10, 50) do |pager|
pager.replace([*1..50].map! { build_stubbed(:measure, station: station) })
end
end
before(:each) do
Measure.stub(:last).and_return(measures.last)
assign(:station, station)
assign(:measures, measures)
stub_user_for_view_test
end
subject {
render
rendered
}
it { should match /Latest measures for #{station.name.capitalize}/ }
it { should match /Latest measurement recieved at #{measures.last.created_at.strftime("%H:%M")}/ }
it { should have_selector '.pagination' }
end
<div class="row">
<h1>Latest measures for <%= @station.name.capitalize %></h1>
<p>Latest measurement recieved at <%= time_date_hours_seconds(@measures.last.created_at) %></p>
<%= render :partial => 'measures/table', object: @measures %>
<%= will_paginate @measures %>
</div>
Did you fix this @maxcal? I'm suffering the same problem.
@Senen yes, but it was a while ago. Don´t remember exactly how I fixed it but i think it involved using locals in the partial which was paginated:
<%= render partial: 'observations/table',
locals: { observations: @observations, station: @station }
%>
https://github.com/remote-wind/remote-wind/blob/master/app/views/observations/index.html.erb
<table class="observations small-12 columns">
<thead>
<th>Time</th>
<th>Direction</th>
<th>Wind Speed</th>
</thead>
<tbody>
<%= render partial: "observations/observation",
collection: observations,
locals: { station: station } if observations.any?
%>
</tbody>
</table>
https://github.com/remote-wind/remote-wind/blob/master/app/views/observations/_table.html.erb
specs are here: https://github.com/remote-wind/remote-wind/tree/master/spec/views/observations
Thank you @maxcal,
I was having problems because in view specs the method :url_for called from will_paginate view helper in index view does not know how to gernerate the url for paginator. It seems there is some kind of problem with nested resources and routes when invoked from rspec spec views.
This could be a bug. Im not really sure yet.
Anyway i already found a solution that works for me:
I stub the method (:url_for) for index view specs, only for nested resources using will_paginate
allow(view).to receive(:url_for).and_return('#')
Example of index view spec for a nested resource. I hope helps anyone.
require 'rails_helper'
require 'will_paginate/array'
RSpec.describe "tricks/index", :type => :view do
context "renders a list of tricks with pagination " do
before(:each) do
@sport = FactoryGirl.create(:sport)
@user = FactoryGirl.create(:user)
@trick_kind = FactoryGirl.create(:trick_kind, sport: @sport)
@paginate = 4
@page = 2
FactoryGirl.create_list(:trick, @paginate + 1, sport: @sport, user: @user, trick_kind: @trick_kind )
@tricks = @sport.tricks.paginate(:page => @page, :per_page => @paginate)
allow(view).to receive(:url_for).and_return('#')
render
end
it " should display data" do
@tricks.each do |trick|
assert_select "span.trick_sport_name", :text => trick.sport.name
assert_select "span.trick_user_nickname", :text => trick.user.nickname
assert_select "span.trick_sport_name", :text => trick.sport.name
assert_select "span.trick_votes_count", :text => trick.votes_for.size
end
end
it " should display last page with one element" do
assert_select ".trick", :count => 1
assert_select ".trick_name", :count => 1
assert_select "iframe", :count => 1
assert_select ".trick_user_nickname", :count => 1
assert_select ".trick_votes_count", :count => 1
end
it " should display pagination" do
assert_select ".pagination", :count => 1
end
it " should have to be active the @page item" do
assert_select "li.active", :count => 1
assert_select "li.active", :text => @page
end
end
end
Thats about the same as my specs. I vaguely remember digging into this and the cause seems to be that RSpec view specs are a thin veneer over ActionView::Testcase (or something similar) which doesn't set up the context for url_for properly. That's why feature specs exercising the same view work.