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

时间:2014-10-21 16:44:07

标签: ruby-on-rails ruby ruby-on-rails-3.2 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。 如何推迟这些提交?

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

------编辑----------

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

  

何时保存对象?

     

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

     

如果要将对象分配给has_and_belongs_to_many   没有保存对象的关联,请使用collection.build   方法

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

1 个答案:

答案 0 :(得分:0)

为什么不在Category回拨中将其移入after_save模型? e.g。

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

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

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