Rails 3 has_and_belongs_to_many关联:如何分配相关对象而不将它们保存到数据库

使用has_and_belongs_to_many_association

class Category has_and_belongs_to_many :projects end 

我想在保存类别之前使用before_filter来设置项目

 before_filter :set_projects, :only => [:create, :update] def set_projects @category.assign_attributes({projects: Project.all}) end 

这种方法很有效,除非无法保存类别并且存在回滚。 项目仍在数据库中更新。

为什么这一行

 @category.assign_attributes({projects: Project.all}) 

立即生成这些数据库记录?

 BEGIN INSERT INTO "categories_projects" ("category_id", "project_id") VALUES (86, 1) INSERT INTO "categories_projects" ("category_id", "project_id") VALUES (86, 2) INSERT INTO "categories_projects" ("category_id", "project_id") VALUES (86, 3) COMMIT 

在提交这些新的categories_projects关系之前,我想等待@ category.save。 如何推迟这些提交?

请注意,我无法修改主“更新”操作。 我必须在filter和回调之前/之后使用,以覆盖我的应用程序的当前function。

——编辑———-

好的,在这里仔细阅读文档后,我想我有一个解决方案:

对象何时保存?

将对象分配给has_and_belongs_to_many关联时,将自动保存该对象(以便更新连接表)。 如果在一个语句中分配多个对象,则它们全部保存。

如果要在不保存对象的情况下将对象分配给has_and_belongs_to_many关联,请使用collection.build方法。

我将尝试使用collection.build方法。 您是否知道如何使用现有项目?

为什么不在after_save回调中将其移入Category模型? 例如

 class Category #based on comment need virtual attribute attr_accessor :assignable_projects after_save :set_projects private def set_projects self.assign_attributes({projects: self.assignable_projects}) end end 

由于您只需要为特定项目设置此项,因此您需要创建一个虚拟属性。 此属性将存储在实例中,但不会保存到数据库中。 为此,我们添加了一个attr_accessor行,它将创建所需的getter和setter方法。

然后在控制器中

 class CategoriesController < ApplicationContoller before_filter :set_assignable_projects, only: [:create,:update] private def set_assignable_projects @category.assignable_projects = params[:project_ids] end end 

运行categoryvalidation并成功保存类别后,将触发此事件。 然后,它将使用before_filter指定的值来创建关联。 由于assign_attributes不会再次调用save ,因此将避免无限循环。 您也可以将其置于after_validation回调中,但请确保检查self.errors.empty? 在使用assign_attributes之前,你将会在同一条船上。

如果category无法保存,则仍会为该实例设置assignable_projects ,以便它们将在渲染视图中显示失败的保存。