feature "comment" do
given(:user) do
build(:user)
end
background do
user1=create(:user)
user1.id=1
login_as(user1)
end
scenario "can create comment" do
@undertake=create(:undertake)
visit undertake_path(@undertake)
within("form#undertake-form-test") do
fill_in "content" , with: "heyheyhey"
end
click_button 'send-btn'
expect(page).to have_content 'heyheyhey'
end
end
这是spec / features / comment_spec.rb。以下是controllers / undertakes_controller.rb。
class UndertakesController < ApplicationController
def show
@undertake=Undertake.find_by(id: params[:id])
@comment=current_user.comments.new
end
以下是views / undertakes / show.html.erb。
<p><%= @undertake.id %></p>
和spec / factories / undertakes.rb。
FactoryGirl.define do
factory :undertake do
association :ask
association :user
id 1
user_id 2
ask_id 1
title "MyString"
content "MyText"
result false
end
end
的routes.rb
resources :asks , except:[:edit, :update] do
resources :undertakes , only:[:create , :show , :destroy] , shallow: true do
resources :comments , only:[:create]
end
end
现在,为什么我有错误ActionView::Template::Error:undefined method id for nil:NilClass
。请帮帮我。
答案 0 :(得分:2)
这里有很多事情可能是潜在的原因,如果不是直接错误的话,它们是非常单一的。
首先关闭名称undertake
是错误的。使用名词形式Undertaking代替型号名称。
永远不要使用find_by(id: params[:id])
。而是使用find(params[:id])
,因为它会引发ActiveRecord::RecordNotFoundError
并在未找到记录的情况下呈现404页面,而不是以nil错误炸毁。
class UndertakingsController < ApplicationController
def show
@undertaking = Undertaking.find(params[:id])
@comment = @undertaking.comments.new
end
end
此外,您应该从@undertaking
创建评论 - 不要通过表单传递用户ID,因为它会让恶作剧用户玩儿童游戏。
而是在创建记录时从会话中分配用户:
class CommentsController
# this assumes you are using Devise
before_action :authenticate_user!
def create
@comment = Comment.new(comment_params) do |c|
c.user = current_user
end
# ...
end
end
这就是你如何用惯用法编写规范。请注意使用已记住的let
帮助程序以及从不将ID分配给记录的事实。这是由数据库完成的。试图手动完成它只会搞砸。
require 'rails_helper'
RSpec.describe 'Comments' do
let(:current_user) { create(:user) }
let(:undertaking) { create(:undertaking) }
background do
login_as(current_user)
end
scenario "can create a comment" do
visit undertaking_path(undertaking)
# Avoid using CSS selectors and instead write specs
# based on what the user sees as it makes specs brittle
within("form#undertake-form-test") do
fill_in "content" , with: "heyheyhey"
click_button 'Create comment'
end
expect(page).to have_content 'heyheyhey'
end
end
使用let
代替@instance
变量。在编写功能,请求和控制器规范时,您需要使用FactoryGirl.create
而不是build
,因为后者不会插入到数据库中,并且该记录实际上不会存在于您的rails应用程序中。
你的工厂定义也严重受损。工厂的整个想法是它应该创建独特,有效的记录。切勿在工厂设置ID。
FactoryGirl.define do
factory :undertaking do
title "MyString"
content "MyText"
user # just reference the factory if you REALLY need the association to exist
ask # just reference the factory if you REALLY need the association to exist
result false # this should probally be set through a DB default instead!
end
end