了解ActiveRecord的存在方式?在建立协会时起作用

时间:2013-01-22 00:58:52

标签: ruby activerecord factory-bot activemodel

我有两个通过has_many关系关联的模型。 E.g。

class Newspaper < ActiveRecord::Base
  has_many :articles
end

class Article < ActiveRecord::Base
  belongs_to :newspaper

  validates :uid, presence: true,
                  uniqueness: { case_sensitive: true }
end

报纸每天更新几次,但我们只想构建和添加尚未存在的协会的文章。以下代码是我实现这一目标的第一步。

new_articles.each do |article|
  unless newspaper.articles.exists? uid: article.uid
    newspaper.articles.build(uid: article.uid)
  end
end

报纸对象是新的和未保存的,或者此时通过现有关系检索。

我的测试表明我能够使用上面的代码在报纸上添加两篇具有相同UID的文章,这显然不是我想要的。

我觉得我的当前代码会在保存时导致验证失败 ,因为验证会查看整个文章表中的唯一性,而不是 >协会

我正在努力理解的是exists?方法在这种情况下的表现(以及为什么它没有像我计划的那样保存我的培根)。我正在使用FactoryGirl来制作一份报纸,添加一篇文章然后模拟包含一篇文章的更新,该文章与我已经添加的文章具有相同的uid。如果代码有效,我应该只获得一篇相关文章,但我得到两篇。使用buildcreate没有任何区别,因此文章记录是否已存在于数据库中似乎不会改变结果。

任何人都可以阐明我如何能够达到理想的结果为什么exists?方法没有达到预期效果?

由于

1 个答案:

答案 0 :(得分:0)

关联exists?实际上会根据关联创建范围查询。这就是您现有文章过滤器不起作用的原因。

unless newspaper.articles.exists? uid: article.uid

# `articles.exists?` here will produce this if the newspaper is new 
#   ... WHERE "articles"."newspaper_id" IS NULL AND "articles.uid" = '<your uid>'

# and this, if the newspaper is persisted (with an id of 1)
#   ... WHERE "articles"."newspaper_id" = 1 AND "articles.uid" = '<your uid>'

新报纸的情况显然是错误的,因为它只返回带有nil报纸ID的文章。但持续存在的情况也可能是不受欢迎的,因为它仍然不必要地过滤报纸ID,当你真正担心的是UID是独特的。

相反,您可能只想反对Article,而不是通过关联确定exists?,例如:

unless Article.exists? uid: article.uid

关于你的其他问题:

  

这似乎是一个FactoryGirl问题,其中create方法没有像我在irb中那样创建数据库条目。

FactoryGirl.create仍应遵守验证。看看你的测试可能会有所帮助。