Rails:使用 where 子句查找深度嵌套的关联

Posted

技术标签:

【中文标题】Rails:使用 where 子句查找深度嵌套的关联【英文标题】:Rails: Finding a deeply nested association with a where clause 【发布时间】:2013-01-25 17:21:09 【问题描述】:

我有两个模型加入了 has_many :through 关系:

class Publication < ActiveRecord::Base
  has_many :publication_contributors
  has_many :contributors, :through => :publication_contributors
end

class Contributor < ActiveRecord::Base
  has_many :publication_contributors
  has_many :publications, :through => :publication_contributors
end

class PublicationContributor < ActiveRecord::Base
  belongs_to :publication
  belongs_to :contributor
end

(关于我的 PublicationContributor 模型的一些不同寻常和重要的地方在于,它不仅有一对数据库 id,它还有一个名为 contributor_type 的字符串属性。这个字符串可以包含诸如“作者”或“翻译者”或“ Publisher”。我不认为这是这里的问题,但解决方案仍然必须解决它。)

我想找到一个具有特定贡献者的出版物,如下所示:

Publication
  .joins(:publication_contributors =>  :contributor)
  .where(:publication_contributors => 
            :contributor_type => "Author", 
             :contributor => :name => params[:authors])

在我到达嵌套的 :contributor 之前一切正常,此时 SQL 会出现问题:

mysql2::Error: Unknown column 'publication_contributors.contributor' in 'where clause'

而不是寻找publication_contributors.contributor_id,而是寻找publication_contributors.contributor,它并不存在。我在我的代码中做错了吗?我找不到像这样具有深度嵌套关联的 where 子句的任何其他示例。也许这根本不可能?

更新:

生成的 SQL

←[1m←[35mPublication Load (0.0ms)←[0m  SELECT `publications`.* FROM `publicati
ons` INNER JOIN `publication_contributors` ON `publication_contributors`.`public
ation_id` = `publications`.`id` INNER JOIN `contributors` ON `contributors`.`id`
 = `publication_contributors`.`contributor_id` WHERE `publication_contributors`.
`contributor_type` = 'Author' AND `publication_contributors`.`contributor` = '--
-\n:name:\n- Marilynne Robinson\n' LIMIT 1

另外,我的 Publications 模型中有这个关联:

has_many :authors, :through => :publication_contributors, :source => :contributor, :conditions => :publication_contributors => :contributor_type => "Author"

我在想我可以这样做:

Publication.joins(:authors).where(:authors => :name => params[:authors])

但这会引发错误:

Mysql2::Error: Unknown column 'authors.name' in 'where clause'

【问题讨论】:

能否发布生成的 SQL 查询? 我认为“作者”是指更新中的“贡献者”? 不,我是说作者。尽管它们不是模型并且没有数据库表,但我仍然使用该名称创建了一个 ActiveRecord 关联,它可以找到具有contributor_type“作者”的贡献者。 【参考方案1】:

尝试改变你的 where 子句:

Publication
  .joins( :publication_contributors => :contributor )
  .where( :publication_contributors => :contributor_type => "Author", 
          :contributors             => :name => params[:authors] ) 

ActiveRecord api 在这里不是非常一致:where 的参数与joins 的参数不完全一致。这是因为joins 的参数确实 反映了底层SQL,而where 的参数确实。

where 接受一个散列,其键是表名,值是散列(它们本身以列名作为键)。它只是在针对两个表中具有相同名称的列时防止歧义。

这也解释了为什么会出现第二个问题:关系authors 不存在。

【讨论】:

就是这样!这个解决方案比我想象的要简单得多。感谢您为我节省了大量时间。 不客气。顺便说一句,如果我没记错的话,我认为您可以直接使用 joins(:authors) 来节省您的打字时间,但您仍然必须在 where 子句中使用“贡献者”。 太棒了!很棒的提示! 它看起来很容易受到 SQL 注入的攻击,比如 params[:authors]1; DROP TABLE.... @Noah_S 不这么认为。除非您正在做一些愚蠢的事情,例如构建自己的 where 字符串,否则 params[:authors] 将被清理

以上是关于Rails:使用 where 子句查找深度嵌套的关联的主要内容,如果未能解决你的问题,请参考以下文章

在 Haskell 中使用嵌套的 `where` 子句

构造一个Rails ActiveRecord where子句

在嵌套结构中使用 where 子句

如何在rails的where子句中包含if条件

Rails ActiveRecord where 子句与 .first 与 .last 在本地与生产

Rails 在带有连接的 where 子句中运行 AND 查询