rails activerecord保存具有唯一性验证的关联模型

时间:2013-04-27 17:05:43

标签: ruby-on-rails ruby validation rails-activerecord

我是铁路的新手。今天我遇到了保存相关模型的问题。

我有两个具有以下关联的模型,Tag模型具有属性'name'的验证角色,是唯一性。

class Product < ActiveRecord::Base
  has_and_belongs_to_many :tags
  validates_associated :tags
end

class Tag < ActiveRecord::Base
  has_and_belongs_to_many :products
  validates :name, :presence => true, :uniqueness => true
end

我要归档的是创建一个与多个标签关联的产品对象。我使用了以下功能:

def self.create_with_tags(value)
    tags = []
    if value.has_key? :tags
    tags = value[:tags]
    value.delete :tags
    end
    p = Product.new(value)
    tags.each do |tag|
      p.tags.build(:name => tag)
    end
    p.save!
    p
end

测试代码是

p = Product.create_with_tags(:name => 'test product', :status => true, :tags =>['tag1','tag2','tag3','tag4']) 

当数据库中不存在标签名称['tag1','tag2','tag3','tag4']时,测试代码正常工作; 如果其中一个标记已存在于数据库中,例如“tag1”,则关联验证将失败,整个创建过程将回滚。

我要归档的是:如果数据库中已存在某些标记,则验证不会失败,而是找到(但不创建)现有标记,并创建产品与现有标记之间的关联。例如,如果'tag1'已经在数据库中,则不会再次创建它,但会创建products_tags表中的关联。

1 个答案:

答案 0 :(得分:0)

我建议将结构与现有结构略有不同:我不是使用类方法作为替代构造方法,而是使用标准Product.new方法作为入口点,并传递Tag实例它作为标准属性。那怎么样:

tag_ids = ['tag1','tag2','tag3','tag4'].map do |t|
  Tag.where(:name => t).first_or_create.id
end
p = Product(:name => 'test product', :status => true, :tag_ids => tag_ids)

使用first_or_create,您可以先检查具有给定名称的Tag是否已存在,如果不存在则创建一个,最后使用内置的Product.new方法而不是使用单独的构造方法(例如你的self.create_with_tags方法。

如果您真的想继续使用self.create_with_tags方法,那么您仍然可以使用first_or_create方法。