2015-06-01 66 views
0

我在测试ratings_controller时遇到了这些错误。ActiveRecord :: RecordNotFound:无法找到没有ID的酒店

1) RatingsController create action creates a rating if validations pass 
    Failure/Error: post :create, rating: {value: 4, user_id: user, hotel_id: hotel} 
    ActiveRecord::RecordNotFound: 
     Couldn't find Hotel without an ID 
    # ./app/controllers/ratings_controller.rb:6:in `create' 
    # ./spec/controllers/ratings_controller_spec.rb:12:in `block (4 levels) in <top (required)>' 
    # ./spec/controllers/ratings_controller_spec.rb:11:in `block (3 levels) in <top (required)>' 

    2) RatingsController create action does not create rating if validations fail 
    Failure/Error: post :create, rating: {value: 3} 
    ActiveRecord::RecordNotFound: 
     Couldn't find Hotel without an ID 
    # ./app/controllers/ratings_controller.rb:6:in `create' 
    # ./spec/controllers/ratings_controller_spec.rb:17:in `block (3 levels) in <top (required)>' 

    3) RatingsController update action updates rating if validations ok 
    Failure/Error: patch :update, value: 3, user_id: user.id, hotel_id: hotel.id 
    ActionController::UrlGenerationError: 
     No route matches {:action=>"update", :controller=>"ratings", :hotel_id=>"1", :user_id=>"2", :value=>"3"} 
    # ./spec/controllers/ratings_controller_spec.rb:25:in `block (3 levels) in <top (required)>' 

我不知道它们来自哪里。如果可以,请帮助我。 我ratings_controller:

class RatingsController < ApplicationController 
    #before_action :signed_in_user 
    before_filter :authenticate_user! 

    def create 
    @hotel = Hotel.find(params[:hotel_id]) 
    @rating = Rating.new(params[:rating]) 
    @rating.hotel_id = @hotel.id 
    @rating.user_id = current_user.id 
    if @rating.save 
     redirect_to hotel_path(@hotel), :notice => "Your rating has been saved" 
    end 
    end 

    def update 
    @hotel = Hotel.find(params[:hotel_id]) 
    #@rating = current_user.ratings.find(@hotel.id) 
    @rating = Rating.find_by_hotel_id(@hotel.id) 
    if @rating.update_attributes(params[:rating]) 
     redirect_to hotel_path(@hotel), :notice => "Your rating has been updated" 
    end 
    end 

end 

我ratings_controller_spec.rb:

require "spec_helper" 

describe RatingsController do 
    let(:rating) { FactoryGirl.create(:rating) } 
    let(:user) { FactoryGirl.create(:user) } 
    let(:hotel) { FactoryGirl.create(:hotel) } 

    describe "create action" do 
    before { sign_in rating.user } 
    it "creates a rating if validations pass" do 
     expect { 
      post :create, rating: {value: 4, user_id: user, hotel_id: hotel} 
     }.to change(Rating, :count).by(1) 
    end 

    it "does not create rating if validations fail" do 
     post :create, rating: {value: 3} 
     expect(response).to redirect_to(hotel_path(hotel)) 
    end 
    end 

    describe "update action" do 
    before { sign_in hotel.user } 
    it "updates rating if validations ok" do 
     patch :update, value: 3, user_id: user.id, hotel_id: hotel.id 
     rating.reload 
     expect(rating.value).to eq(3); 
    end 

    it "updates rating if validations fail" do 

    end 
    end 
end 

尤其是第三个错误困惑我,因为rake routes显示了评级更新动作我avaible路线。

PATCH /hotels/:id(.:format)  hotels#update 
PUT /hotels/:id(.:format)  hotels#update 

谢谢!

Rails - 4.0.8 Ruby - 1.9.3p551

UPDATE 1: 对不起路由。我的mystake。只是复制了错误的行。

rating PATCH /ratings/:id(.:format) ratings#update 
     PUT /ratings/:id(.:format) ratings#update 

似乎对我来说很好,如果我启动服务器并手动测试它,它工作正常。

回答

1

关于ID的问题:

@hotel = Hotel.find(params[:hotel_id])预计params哈希有一个顶级hotel_id关键。当你调用从测试的create方法,您嵌套hotel_idratings键:

post :create, rating: {value: 4, user_id: user, hotel_id: hotel}

因此params[:hotel_id]为零。您需要将hotel_id添加为顶级项:

post :create, rating: {value: 4, user_id: user, hotel_id: hotel}, hotel_id: hotel

或者,你可以直接通过嵌套hotel_idfind方法:

@hotel = Hotel.find(params[:rating][:hotel_id])

关于路线的问题:

您的路线被映射到HotelsController(如在rake routes输出视为hotels#update),但是您正在测试RatingsController,因此您可以获得

No route matches {:action=>"update", :controller=>"ratings", :hotel_id=>"1", :user_id=>"2", :value=>"3"}

更新你的路由路由到RatingsControllerupdate方法,而不是HotelsController,所以你将有一个ratings#update路线。

更新:

在这种情况下,路由期待在URL中id参数:/ratings/:id,你不提供:

patch :update, value: 3, user_id: user.id, hotel_id: hotel.id

要么提供一个特定的等级标识你想更新或改变你的路线,不要求id参数,因为你无论如何都会通过酒店找到评级,所以他们看起来像

patch '/ratings', to 'ratings#update'

,而不是

patch '/ratings/:id', to 'ratings#update'

如果你用resources :ratings定义了你的路由,你可以把特定的路由放在它的上面,这样它将首先被路由器命中。一个好主意是排除它:resources :ratings, except: :update。或者只是使用collection routes。有关更多信息,请参阅this question

+0

谢谢你的回答。对路线抱歉。我复制了错误的行。请检查出这个帖子。 –

+0

更新是否能解决您的问题? – p4sh4

相关问题