Rails 预览更新关联而不保存到数据库

Rails preview update associations without saving to database

我想预览保存时模型的外观,但当前未保存到数据库。

我正在使用 @event.attributes =,因为它会将 @event 的属性分配但不会保存到数据库。

但是,当我也尝试分配 audiences 关联时,Rails 将新记录插入 audiences_events 连接 table。不酷。有没有办法在不插入连接的情况下预览这些新关联的外观 table?

型号

class Event < ActiveRecord::Base
  has_and_belongs_to_many :audiences # And vice versa for the Audience model.
end

控制器

class EventsController < ApplicationController 

  def preview
    @event = Event.find(params[:id])
    @event.attributes = event_params
  end

  private
    def event_params
      params[:event].permit(:name, :start_time, :audiences => [:id, :name]
    end

end

可能的解决方案?

我想到但不知道怎么做的可能解决方案:

任何有关这些的帮助都会很棒!

更新:
阅读下面的精彩答案后,我最终编写了此服务 class,它将非嵌套属性分配给事件模型,然后在每个嵌套参数上调用 collection.build。我做了一个小要点。很高兴收到 comments/suggestions.

https://gist.github.com/jameskerr/69cedb2f30c95342f64a

在这些docs中你有:

When are Objects Saved?

When you assign an object to a has_and_belongs_to_many association, that object is automatically saved (in order to update the join table). If you assign multiple objects in one statement, then they are all saved.

If you want to assign an object to a has_and_belongs_to_many association without saving the object, use the collection.build method.

这是 Rails 3 的一个很好的答案,它解决了一些相同的问题

Rails 3 has_and_belongs_to_many association: how to assign related objects without saving them to the database

交易

创建 transactions 非常简单:

Event.transaction do
  @event.audiences.create!
  @event.audiences.first.destroy!
end

@event.transaction do
  @event.audiences.create!
  @event.audiences.first.destroy!
end

注意 "bang" 方法 create!destroy! 的使用,与 create 不同 returns false create! 会引发异常如果失败导致事务回滚。

您还可以通过引发 ActiveRecord::Rollback 在事务中的任何位置手动触发回滚。

建造

build 实例化一个新的相关对象而不保存。

event = Event.new(name: 'Party').audiences.build(name: 'Party People')
event.save # saves both event and audiences

我知道这是一个很老的问题,但我找到了一个非常适合我的解决方案,希望它能为其他人节省时间:

class A
  has_many :bs, class_name 'B'
end

class B
  belongs_to :a, class_name: 'A'
end

a.bs.target.clear
new_bs.each {|new_b| a.bs.build new_b.attributes.except('created_at', 'updated_at', 'id') }

您将避免 Rails 在您执行 a.bs = new_bs

时执行的自动保存