I'm using the latest versions of Rails, Rspec and Factory Girl and I'm getting a strange issue when I try to test my create or update logic. The controller in question is an Admin namespaced PostsController and the model is Post. The factory itself just creates a post with a title and a body.
describe 'create' do
before :all do
#new = Factory.build(:post)
end
it 'should be successful' do
post :create, :post => #new
response.should be_success
end
describe 'failure' do
it 'should not create a new page' do
lambda do
post :create, :post => #new
end.should_not change(Post, :count)
end
it 'should render the new template' do
post :create, :post => #new
response.should render_template('new')
end
end
end
The error I keep receiving is:
ActiveRecord::UnknownAttributeError:
unknown attribute: post
I'm probably doing something extremely stupid but I'm just lost right now.
UPDATE
Just in case anyone should ever stumble across this...
I was doing something extremely stupid. I had an error in my controller where instead of calling Post.new(params[:post]) I was calling Post.new(params)...
It would help to know what line it's failing on. If it's failing in the 'before :all' block, then the problem is probably in your factory code, which is presumably specifying a value for a non-existent 'post' attribute of the model.
If that's what the factory is doing, but the 'post' attribute actually should exist, then perhaps you ran this using rspec from the command line without running rake db:test:prepare first. In that case, your 'posts' table structure might not be up to date.
Related
Im trying to set up a (basic) test for a new feature I am going to implement. I have a job controller and instead of default showing all jobs I like to hide all the ones which is archived. I tried different ways but it seems like i am missing a piece or two of this puzzle. First i tried with calling 'visit' but get the message it does not exist. Second approach is using 'render' but that also ends up in a error saying render does not exists. (can i even use these methods in a controller spec?)
Is it wrong to put this in a controller test?
2 last test are causing errors
require "rails_helper"
require "spec_helper"
describe JobsController, :type => :controller do
context 'GET index' do
it "should be successful" do
get :index
expect(response).to be_success
end
it "renders the index template" do
get :index
expect(response).to render_template("index")
end
it "should not show any archived jobs as default" do
visit jobs_path
page.should have_no_content("Archived")
end
it 'should show the headers' do
render :template => 'job/index', :layout => 'layouts/job'
rendered.should_not contain('Archived')
end
end
end
Capybara is used for feature specs, and its matchers can be used in view specs.
Controller specs, by default, don't actually render the view because they're the wrong place to be checking for page content - https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs
You should probably move some of your tests to feature tests/view tests
I'm trying to set up specs to properly run with my nested resource.
This is the test code I'm trying to properly set up
it "redirects to the created unit" do
post :create, {:course_id => #course.id , :unit => valid_attributes}
response.should redirect_to(course_unit_path(#course, Unit.last))
end
That essentially should try to create a nested resource "unit" for "course".
Unfortunatly I'm getting the following error on all POST DELETE and PUT tests
Failure/Error: post :create, {:course_id => #course.id , :unit => valid_attributes}
NoMethodError:
undefined method `unit_url' for #<UnitsController:0x000000059f1000>
That makes sense since unit_url should be course_unit_url but it's RSpec calling it...
How can I make RSpec select the right named path?
For all GET tests I passed the :course_id by hand.
This is what I did:
it "redirects to the created unit" do
unit_id = "barry"
Unit.any_instance.should_receive(:save).and_return(true)
Unit.any_instance.stub(:id).and_return(unit_id)
post :create, {:course_id => #course.to_param , :unit => valid_attributes}
response.should redirect_to(course_unit_path(#course, unit_id))
end
I decided that the point of this test was not that it created a new model and redirected it, but simply that it redirects. I have another spec to ensure it creates a new model. Another benefit to this approach is that it doesn't touch the database so it should run a little faster.
I hope that helps.
Edit:
I also just noticed I have this in my before :each section which may be relevant:
Course.stub!(:find).and_return(#course)
Edit again:
In this case, there was code in the controller which was doing the offending call. As per comment below.
I am trying to replace user profile views of the sort
/users/1
with
/username
I'm aware this means I'll need to check for collisions of various kinds. I've consulted the following similar SO questions:
Ruby on rails routing matching username
customize rails url with username
Routing in Rails making the Username an URL:
routing error with :username in url
Here are the various failed routes.rb route definitions I've tried, and associated errors:
match "/:username" => "users#show", via: "get"
Here's the error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User without an ID
app/controllers/users_controller.rb:7:in `show'
Here is my corresponding users_controller:
6 def show
7 #user = User.find(params[:id])
8 end
match "/:username" => 'users#show', :as => :profile
Same error as above.
match "/:username", :controller => "users/:id", :action => 'show'
Routing Error
uninitialized constant Users
Try running rake routes for more information on available routes.
match '/:username', :controller => 'users', :action => 'show'
Same error as 1.
match '/:username', to: 'users/:id', via: 'show'
Server does not start.
match "/:username" => redirect("/users/:id")
Error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with id=:id
Any idea why my routing is not working the same way that everyone else who asks this question's is?
Update
Just to take this issue out of the comments and put it in the question more cleanly. After making the change by #Ryan Bigg below, I had a routing problem in my redirect to profile when a new one is created. Here's my create code:
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
flash[:success] = "Thank you for signing up."
redirect_to ('/'+#user.username)
#redirect_to #user, notice: "Thank you for signing up!"
else
render "new"
end
end
And here is my user.rb
def to_param
self.username
#username
end
However, the commented out redirect, which I think should work with the to_param update, doesn't work, while the ugly hackish one above it does. Why is the to_param overwrite, which worked for other people, not working on my app? My #update and #edit methods are also not working, as their redirects go to "users/1/edit" instead of "username/edit" if overwriting to_param doesn't take care of this.
The first one is correct, but isn't working because you're still attempting to do something like this inside your controller:
User.find(params[:username])
When you should instead be doing this:
User.find_by_username!(params[:username])
The first one will attempt to find by the primary key of your table, where the second one will, correctly, query on the username field instead.
In addition to the update for to_params, the bottom of the routes file needs the following line:
resources :users, :path => '/'
I'm trying to move to rspec for testing, but I can't get controller testing to work with user authentication. Testing a route that doesn't require a user works.
require 'spec_helper'
describe UddsController do
include Devise::TestHelpers
render_views
before (:each) do
#user = User.new(:email => "test#user.com", :username => "test123")
#user.roles << Role.find_or_create_by_name("admin")
#user.save
sign_in #user
end
it "should get index" do
get :index
response.should be_success
end
I just get
2) UddsController should get index
Failure/Error: response.should be_success
expected success? to return true, got false
# ./spec/controllers/udds_controller_spec.rb:21
I'm not using factory_girl. All the example fixes here and on google seem to. I don't see why what I've done wouldn't work. Error is useless in debugging.
I know this question has been asked to death. I've read every blog and forum I can find. I'm at a dead end.
It might be redirecting. be_success returns false for any non-2xx status codes (like 302). Try checking the value of response.status -- if it's redirecting, it probably means your authentication or authorization scheme is producing an unexpected result.
Try adding puts response.body before your assertion, and see what the page you are requesting says. If you can't figure it out from there, perhaps edit your question to include the output?
If you are using devise's "confirmable" module which makes users click a link in an email to confirm their address, then when you use "sign_in" in the tests you also have to fake email confirming. It looks something like this:
sign_in #user
#user.confim!
I'm working through Michael Hartl's excellent tutorial on Rails, but I am having trouble with exercise 7 in Chapter 11.
This exercise is:
Add a nested route so that
/users/1/microposts shows all the
microposts for user 1. (You will also
have to add a Microposts controller
index action and corresponding view.)
I've done this successfully by changing my routes.rb file to read:
resources :users do
resources :microposts, :only => [:create, :destroy]
end
I am able to successfully call /users/1/microposts from a browser. However, most of the tests in microposts_controller_spec.rb are now broken. I receive the "no route matches" error when running autotest. For instance, the first test, which simply reads:
it "should deny access to 'create'" do
post :create
response.should redirect_to(signin_path)
end
now produces the following error:
1) MicropostsController access
control should deny access to 'create'
Failure/Error: post :create
No route matches {:controller=>"microposts",
:action=>"create"}
When I check rake routes
, I find this entry:
user_microposts POST /users/:user_id/microposts(.:format) {:action=>"create", :controller=>"microposts"}
which suggests the route does exist.
Has anyone else run into this issue while completing the tutorial? Is there a change I need to make in the spec file once I introduce nested routes? Does Rspec work with nested routes?
thanks
Because this is a nested route you will need to pass the user_id through:
some_user = way_of_creating_a_user_goes_here
post :create, :user_id => some_user.id
RSpec will attempt to go to the /microposts route without this parameter.