一对多关联对象不会保存

时间:2014-12-01 00:47:11

标签: ruby-on-rails

我在我的两个模型中建立了一个has_many belongs_to关系,并跟随Ryan Bates'关于如何设置控制器的截屏视频。当我提交表单来创建新对象时,嵌套对象由于某种原因不能保存。这是我的模特:

class Auction < ActiveRecord::Base
  has_many :bids, dependent: :destroy
end

class Bid < ActiveRecord::Base
  belongs_to :auction
  belongs_to :user
  default_scope -> { order(created_at: :desc) }
  validates :user_id, presence: true
  validates :auction_id, presence: true
end 

和我的嵌套对象控制器:

  class BidsController < ApplicationController
  def index
    @auction = Auction.find(params[:auction_id])
    @bids = @auction.bids
  end

  def new
    @auction = Auction.find(params[:auction_id])
    @bid = @auction.bids.build
  end

  def create
     @auction = Auction.find(params[:auction_id])
    @bid = @auction.bids.create(params[:bid])
    @bid.save
    if @bid.save
      flash[:success] = "Bid has been successfully placed."
    else
      @bid.errors
      render 'new'
    end
  end

  def destroy
     @auction = Auction.find(params[:auction_id])
     @bid = @auction.bids.find
    @bid.destroy
    flash[:notice] = "Successfully destroyed Bid."
    redirect_to auction_url(@bid.article_id)
  end
end

我的表格:

<h1>Create a New Bid</h1>
<%= form_for ([@auction, @bid]) do |f|%>
<p>
<%= f.submit %>
</p>
<%end%>

和我的终端输出:

Started POST "/auctions/1/bids" for 127.0.0.1 at 2014-11-30 17:59:13 -0600
Processing by BidsController#create as HTML
  Parameters: {"utf8"=>"✓",   "authenticity_token"=>"dkZBcab1rgZjtJGF3LAJ//exK6liglZ0Fy4mg7HWEt0=", "commit"=>"Create Bid", "auction_id"=>"1"}
  Auction Load (0.1ms)  SELECT  "auctions".* FROM "auctions"  WHERE "auctions"."id" = ? LIMIT 1  [["id", 1]]
  (0.0ms)  begin transaction
  (0.0ms)  commit transaction
  (0.0ms)  begin transaction
  (0.0ms)  rollback transaction
  (0.0ms)  begin transaction
  (0.0ms)  rollback transaction

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

您的出价对象需要user_id,因为您在类定义中有validates :user_id, presence: true

但是,当您在控制器中调用@bid.save时,@bid没有user_id值,因此由于验证失败而导致事务回滚。

在调用@bid.errors.full_messages后,您应该可以通过查看创建操作中的@bid.save来查看此内容。 (如果您还不熟悉它,请查看撬宝石......这将是一个让您进行此检查的完美工具。)

尝试用以下方法替换您的创建操作:

def create
  @auction = Auction.find(params[:auction_id])
  @bid = @auction.bids.new params[:bid].merge(user_id: current_user.id)
  if @bid.save
    flash[:success] = "Bid has been successfully placed."
  else
    flash[:error] = @bid.errors.full_messages.join('. ')
    render 'new'
  end
end

这假设您可以访问控制器中的当前用户current_user。设计和其他流行的auth解决方案提供此功能,或者您可以自己提供。

另请注意,您的原始代码会尝试将@bid分别写入数据库3次,这比您需要的时间多两倍。以下是违规行:

def create 
  ...
  @bid = @auction.bids.create(params[:bid])
  @bid.save
  if @bid.save
  ...

#create实例化一个对象并尝试将其写入数据库。在上面的代码中,我已将@auction.bids.create(params...)替换为@auction.bids.new(params...)。这会初始化@bid,而不会尝试将其持久保存到数据库中。

我还删除了第一个@bid.save,因为if @bid.save下面的行会完成同样的事情。

最后,您的第@bid.errors行没有做任何有用的事情。我修改它以将错误消息存储在您的flash哈希中,然后您可以在视图中使用它来向用户显示错误。