2013-04-27 555 views
1

我是一个新手入门。今天我遇到了一个保存相关模型的问题。rails activerecord保存有唯一性验证的关联模型

我有以下关联的2个模型,标记模型具有属性“名称”的验证角色为唯一性。

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', '标签2', '标签3', 'TAG4']在数据库中不存在; 如果其中一个标签已经存在于数据库中,例如'tag1',那么关联验证将失败并且整个创建过程都会回滚。

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

+0

参照这个帖子找到最佳答案://stackoverflow.com/questions/4730493/rails-has-and-belongs-to-many-habtm-create-association-without-creating-ot – fuyi 2013-04-27 20:06:55

回答

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,可以先检查是否有给定名称的标签存在不已,如果没有创建一个,最后使用内置Product.new方法,而不是一个单独的构造方法(如您的self.create_with_tags方法)。

如果您确实想继续使用self.create_with_tags方法,那么您仍然可以在那里使用first_or_create方法。 HTTP: - : [Rails的:不会产生其他记录创建协会已经属于多(HABTM)] [1] [1]

+1

谢谢。我需要在attr_accessible中设置:标记以使第二行代码有效。 – fuyi 2013-04-27 19:59:11

+0

哎呀,我应该通过:tag_ids,我已经更新了我的答案以上的修复 – 2013-04-27 20:29:19

相关问题