我在测试ratings_controller时遇到了这些错误。
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
向我显示了评级更新操作的可用路径。
PATCH /hotels/:id(.:format) hotels#update
PUT /hotels/:id(.:format) hotels#update
谢谢!
Rails - 4.0.8
Ruby - 1.9.3p551
更新1: 抱歉路线。我的秘密只是复制了错误的行。
rating PATCH /ratings/:id(.:format) ratings#update
PUT /ratings/:id(.:format) ratings#update
对我来说似乎没问题,如果我启动服务器并手动测试它就可以正常工作。
答案 0 :(得分:1)
@hotel = Hotel.find(params[:hotel_id])
期望params
哈希值具有顶级hotel_id
密钥。从测试中调用create
方法时,将hotel_id
嵌套在ratings
键内:
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_id
直接传递给find
方法:
@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"}
。
更新您的路线以转到RatingsController
的{{1}}方法,而不是update
,因此您将拥有HotelsController
路线。
<强>更新强>
在这种情况下,路线预计网址中的ratings#update
参数:id
,您未提供该参数:
/ratings/:id
要么提供您想要更新的特定评级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
。或者只使用collection routes。有关详细信息,请参阅this question。