Rails:如何以事务方式将has_many关联添加到现有模型?

时间:2012-12-04 18:35:46

标签: ruby-on-rails-3 associations has-many belongs-to

让我们想象一下,我运行了一个假想的艺术商店,里面有几个模特(模特我指的是Rails术语而不是裸体模特中的艺术术语)看起来像这样:

class Artwork < ActiveRecord::Base
  belongs_to :purchase
  belongs_to :artist
end

class Purchase < ActiveRecord::Base
  has_many :artworks
  belongs_to :customer
end

Artwork已创建,稍后它会包含在Purchase中。在我create的{​​{1}}或update控制器方法中,我想将新的Purchase与现有的Purchase相关联。

如果Artwork不存在,我可以Artwork@purchase.artworks.build,但这些都假设我正在创建一个新的@purchase.artworks.create我不是。我可以添加现有的艺术作品:

Artwork

但是,这不是交易性的。数据库立即更新。 (除非我当然在params[:artwork_ids].each do |artwork| @purchase.artworks << Artwork.find(artwork) end 控制器中,在这种情况下,我认为可以“交易”完成,因为create在我打电话给@purchase之前不存在,但那不是我帮助save。)还有update方法,但这也很快。

我认为这样的事情适用于@purchase.artwork_ids=动作,但它非常不优雅。

update

接下来是传统的:

@purchase = Purchase.find(params[:id])
result = @purchase.transaction do
  @purchase.update_attributes(params[:purchase])
  params[:artwork_ids].each do |artwork|
    artwork.purchase = @purchase
    artwork.save!
  end
end

我正在寻找的是类似于从另一个方向起作用的方式,我可以将if result redirect_to purchase_url(@purchase), notice: 'Purchase was successfully updated.' } else render action: "edit" end 放入我的模型中,然后调用accepts_nested_attributes_for,一切都像魔法一样。

2 个答案:

答案 0 :(得分:1)

我找到了一种方法来做我想要的,相当优雅。我需要对Product MVC的每个部分进行更新。

型号:

attr_accessible: artwork_ids

我必须将art_ids添加到attr_accessible,因为之前没有包含它。

查看:

= check_box_tag "purchase[artwork_ids][]", artwork.id, artwork.purchase == @purchase

在我看来,每个艺术作品都有一个check_box_tag的数组。我无法使用check_box,因为没有检查框会导致隐藏值“true”被发送而不是艺术品ID。但是,这使我无法从购买中删除所有艺术作品。执行update时,如果取消选中每个复选框,则params[:purchase]哈希将没有:artwork_ids条目。

控制器:

params[:purchase][:artwork_ids] ||= []

添加此选项可确保设置该值,并具有删除所有现有关联所需的效果。但是,这会导致令人讨厌的rspec失败 Purchase.any_instance.should_receive(:update_attributes).with({'these' => 'params'})失败,因为:update_attributes实际收到{"these"=>"params", "artwork_ids"=>[]})。我尝试在视图中设置hidden_value_tag,但无法让它工作。我认为这个问题值得一个新问题。

答案 1 :(得分:0)

最好使用将购买模型作为连接表并具有多对多关联。

以下是您的用例示例。

客户模式

    has_many :purchases

    has_many :artwork, :through => :purchase

艺术品模型

    has_many :purchases

    has_many :customers, :through => :purchase

购买模式

    belongs_to :customer
    belongs_to :artwork

购买模型应包含customer_id和artwork_id。

您还需要创建一个允许您创建新购买对象的购买控制器。

当客户按下购买按钮时,它将创建一个新的购买对象,其中包括customer_id和artwork_id。这允许您在客户和他们购买的艺术品之间创建关联。您还可以使用price_paid列来保存客户在购买时支付的价格。

如果您需要更多帮助,可以使用以下方法研究加入多对多关联:

希望有所帮助