rspec,undefined方法`id'为零:NilClass

时间:2016-12-13 13:40:47

标签: ruby-on-rails ruby rspec undefined

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。请帮帮我。

1 个答案:

答案 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