【问题标题】:Why is #create failing on this FactoryGirl object?为什么 #create 在此 FactoryGirl 对象上失败?
【发布时间】:2017-06-05 12:53:10
【问题描述】:

我正在尝试测试 Quotes#create 控制器操作,但无法理解失败。我正在使用 Devise 和 FactoryGirl 以及 Quotes 模型 belongs_to :user。 rspec 失败消息是No route matches {:action=>"show", :controller=>"quotes", :id=>nil} missing required keys: [:id]。 FactoryGirl 创建的 Quote 对象传递给用户:

let(:user) { FactoryGirl.create(:user) }
let(:quote) { FactoryGirl.create(:quote, user: user) }

似乎记录没有保存在数据库中,因此记录 [:id] 也不能被传回以呈现给 show 动作。

任何指导表示赞赏。

quotes_controller.rb

class QuotesController < ApplicationController
  before_action :authenticate_user!, only: [ :new, :create, :edit, :update, :destroy ]
  before_action :owners_only, only: [ :edit, :update, :destroy ]

  def new
    @quote = Quote.new
  end

  def create
    # @quote = @user.quotes.new(quote_params)
    @quote = Quote.new(quote_params)
    if @quote.save
        redirect_to quote_url(@quote), notice: 'Quote request created'
    else
      render :new
    end
  end

  def show
    @quote = Quote.find(params[:id])
  end

  def index
    @quotes = Quote.all
  end

  def edit
  end

  def update
    if @quote.update_attributes(quote_params)
      redirect_to quote_path(@quote)
    else
      render :edit
    end
  end

  def destroy
    @quote.destroy
    redirect_to quotes_path
  end

private

  def quote_params
    params.require(:quote).permit(:gla, :prev_cover, :co_name, :co_number, :postcode, :industry, :lives_overseas, 
                                  :scheme_start_date, :payment_frequency, :commission_level)
  end

  def owners_only
    @quote = Quote.find(params[:id])
    if current_user != @quote.user
      redirect_to quotes_path
    end
  end
end

quote.rb 模型:

class Quote < ApplicationRecord
    belongs_to :user

    enum industry:          [ :financial_services, :architect, :business_consultancy ]
    enum payment_frequency: [ :annually, :monthly ]
end

users.rb:

FactoryGirl.define do
  factory :user do
    sequence(:email) { |n| "test#{}@tes.com" }
    password "12345678"

    factory :user2 do
    end
  end
end

quotes.rb

FactoryGirl.define do
  factory :quote do
    prev_cover true
    sequence(:co_name) { |n| "Acme Co #{n}" }
    co_number 9999
    postcode "al1 1aa"
    industry :financial_services
    lives_overseas true
    scheme_start_date "2018-01-01"
    payment_frequency :monthly
    commission_level 12
    gla 1

    factory :quote2 do
    end
  end
end

quote_controller_spec.rb

RSpec.describe QuotesController, type: :controller do
    describe "signed in user" do

        let(:user) { FactoryGirl.create(:user) }
        let(:quote) { FactoryGirl.create(:quote, user: user) } #user.id not getting through here?

        before do
            sign_in(user)
        end

        describe "POST create" do

            context "valid data" do
                let(:valid_data) { FactoryGirl.attributes_for(:quote) } #user.id not getting through here?
                it "redirects to quote#show" do
                    post :create, params: { quote: valid_data }
                    expect(response).to redirect_to(quote_path(assigns[:quote]))
                end

                it " creates a new quote in the database" do
                    expect {
                        post :create, params: { quote: valid_data }
                    }.to change(Quote, :count).by(1)
                end
            end
        end
    end
end

rspec 输出:

 1) QuotesController signed in user POST create valid data redirects to quote#show
     Failure/Error: expect(response).to redirect_to(quote_path(assigns[:quote]))

     ActionController::UrlGenerationError:
       No route matches {:action=>"show", :controller=>"quotes", :id=>nil} missing required keys: [:id]
     # ./spec/controllers/quotes_controller_spec.rb:46:in `block (5 levels) in <top (required)>'

  2) QuotesController signed in user POST create valid data  creates a new quote in the database
     Failure/Error:
       expect {
        post :create, params: { quote: valid_data }
       }.to change(Quote, :count).by(1)

       expected #count to have changed by 1, but was changed by 0
     # ./spec/controllers/quotes_controller_spec.rb:50:in `block (5 levels) in <top (required)>'

似乎 user_id 没有通过 :valid_data 对象let(:valid_data) { FactoryGirl.attributes_for(:quote) }。尽管:quote 对象在以下位置被赋予了 :user 对象:

let(:user) { FactoryGirl.create(:user) }
let(:quote) { FactoryGirl.create(:quote, user: user) }

它只是没有通过,我认为这就是问题所在,有什么建议吗?

【问题讨论】:

  • 在控制器中使用 if @quote.save! 会得到什么?
  • 我的记录无效ActiveRecord::RecordInvalid: Validation failed: User must exist # ./app/controllers/quotes_controller.rb:11:in "create"。是let(:quote) 已将user: user 传递给#create,它只是没有通过吗?我想知道还有其他方法可以解决这个问题吗?
  • 或者与quotes_controller.rb中的#owners_only有关!?
  • 如果报价属于用户,则应通过用户创建报价。例如,current_user.quotes.new(quote_params)@user 如果您没有 #current_user 辅助方法(我推荐!)。
  • #owners_only 要求 id 已经存在引用,如果您在创建操作中,则没有与引用相关的 params[:id]

标签: ruby-on-rails-3 authentication devise factory-bot


【解决方案1】:

根据您的 cmets,我建议您将创建操作更改为:

def create @quote = current_user.quotes.new(quote_params) if @quote.save redirect_to quote_url(@quote), notice: 'Quote request created' else render :new end end

【讨论】:

  • ` NoMethodError: undefined method "quotes" for #<0x007fff2bd36170>
  • &lt;&gt;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 2014-11-23
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多