Rails 防止多态 has_many 中的重复:通过关联
是否有一种简单或至少优雅的方法来通过关联防止多态 has_many 中的重复条目?
我有两个可以标记的模型、故事和链接。我有意识地决定不在这里使用插件。我想真正理解正在发生的一切,而不是依赖于我不完全掌握的其他人的代码。
要了解我的问题是什么,如果我在控制台中运行以下命令(假设故事和标签对象已存在于数据库中),
s = Story.find_by_id(1)
t = Tag.find_by_id(1)
s.tags << t
s.tags << t
我的标记连接表将添加两个条目,每个条目具有相同的确切数据(tag_id = 1,taggable_id = 1,taggable_type =“故事”)。这对我来说似乎不太合适。因此,为了防止这种情况发生,我在标记模型中添加了以下内容:
before_validation :validate_uniqueness
def validate_uniqueness
taggings = Tagging.find(:all, :conditions => { :tag_id => self.tag_id, :taggable_id => self.taggable_id, :taggable_type => self.taggable_type })
if !taggings.empty?
return false
end
return true
end
它几乎按预期工作,但如果我尝试向故事或链接添加重复标记,我会收到 ActiveRecord::RecordInvalid: Validation failed 异常。似乎当您将关联添加到列表时,它会调用保存! (而不是 save sans !)如果出现问题,该方法会引发异常,而不仅仅是返回 false。这并不是我想要发生的事情。我想我可以用 try/catch 包围任何添加新标签的尝试,但这违背了您不应该期望出现异常的想法,而这是我完全希望发生的事情。
当我想做的只是因为存在重复项而默默地不将对象保存到数据库时,是否有更好的方法来执行此操作,不会引发异常?
Is there an easy or at least elegant way to prevent duplicate entries in polymorphic has_many through associations?
I've got two models, stories and links that can be tagged. I'm making a conscious decision to not use a plugin here. I want to actually understand everything that's going on and not be dependent on someone else's code that I don't fully grasp.
To see what my question is getting at, if I run the following in the console (assuming the story and tag objects exist in the database already)
s = Story.find_by_id(1)
t = Tag.find_by_id(1)
s.tags << t
s.tags << t
My taggings join table will have two entries added to it, each with the same exact data (tag_id = 1, taggable_id = 1, taggable_type = "Story"). That just doesn't seem very proper to me. So in an attempt to prevent this from happening I added the following to my Tagging model:
before_validation :validate_uniqueness
def validate_uniqueness
taggings = Tagging.find(:all, :conditions => { :tag_id => self.tag_id, :taggable_id => self.taggable_id, :taggable_type => self.taggable_type })
if !taggings.empty?
return false
end
return true
end
And it works almost as intended, but if I attempt to add a duplicate tag to a story or link I get an ActiveRecord::RecordInvalid: Validation failed exception. It seems that when you add an association to a list it calls the save! (rather than save sans !) method which raises exceptions if something goes wrong rather than just returning false. That isn't quite what I want to happen. I suppose I can surround any attempts to add new tags with a try/catch but that goes against the idea that you shouldn't expect your exceptions and this is something I fully expect to happen.
Is there a better way of doing this that won't raise exceptions when all I want to do is just silently not save the object to the database because a duplicate exists?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你可以通过几种方式做到这一点。
定义一个自定义 add_tags 方法,加载所有现有标签,然后检查并仅添加新标签。
示例:
您还可以使用 before_save 过滤器来确保标签列表没有任何重复项。这会产生更多的开销,因为它会在每次保存时发生。
You could do it a couple of ways.
Define a custom add_tags method that loads all the existing tags then checks for and only adds the new ones.
Example:
You could also use a before_save filter to ensure that the list of tags doesn't have any duplicates. This would incur a little more overhead because it would happen on EVERY save.
您可以在定义 has_many 关系时设置 uniq 选项。 Rails API 文档说:
(摘自:http://api.rubyonrails.org/classes/ ActiveRecord/Associations/ClassMethods.html#M001833 在“支持的选项”小标题下)
You can set the uniq option when defining has_many relation. Rails API docs says:
(taken from: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001833 under "Supported options" subheading)
我相信这有效...
如果您遇到任何错误或其他问题,请告诉我:]
I believe this works...
Let me know if you get any errors or something with that :]