在嵌套表单中强制实施唯一性约束

时间:2010-02-25 03:54:02

标签: ruby-on-rails

我试图不在这里对抗默认值并使用Rails内置支持嵌套属性(来自http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes)。我用标签标记了东西,并且所有作品都膨胀了,对于每个东西我都有一个带有嵌套字段的表单,它通过名称创建一个新的标签。麻烦的是,我需要确保每个标签都有一个唯一的名称。如果用户输入已存在的名称,我需要创建与该预先存在的标签的关联,而不是创建新标签。我该怎么做?

2 个答案:

答案 0 :(得分:1)

这可能是一种更好的方法,但这是我现在能想到的最好的方法。

在has_many(:through)关联中,accepts_nested_arguments_for使用对虚拟属性#{association}_attributes的赋值来实现其魔力。它需要一个哈希数组,其中每个哈希都包含属性键及其值。任何具有id的哈希都将被更新(如果存在值为true的:_delete键,则会被删除)。任何缺少id的哈希都将用于创建该关联的新项目。因此,关键是截取对tags_associations=的调用,并检查具有相同名称值的现有标记缺少id的任何哈希值,并将其替换为tags_attributes将用于与之关联的条目。现有标签。对于has_one和belongs_to关系 N.B。,tag_attributes将需要一个哈希值。代码将类似,但更简单。

class Thing < ActiveRecord::Base
  has_many :tags, :through => :taggings
  has_many :taggings
  accepts_nested_attributes_for :tags

  def tags_attributes_with_recycling=(attributes)
    existing_attributes = attributes.reject{|attribute| attribute[:id].nil?}
    new_attributes = attributes - existing_attributes
    new_and_recycled_attributes = new_attributes.map { |attribute| 
      tag_id = Tag.find_by_name(attribute[:name]).id
      tag_id ? {:id => tag_id) : attribute
    }
    tags_attributes_without_recycling= (existing_attributes + new_and_recycled_attributes)
  end

  alias_method_chain :tags_attributes=, :recycling
end

这是未经测试的,所以没有保证。但它至少应该让你找到解决方案。

答案 1 :(得分:1)

在你的Thing类中,定义一个tags_attributes =方法来覆盖默认值并使用Tag.find_or_create

def tags_attributes=(attributes)
  attributes.each do |attr|
    Tag.find_or_create_by_name(attr[:name])
  end
end

不确定属性hash会是什么样子但你明白了。