解构Rails。加入& .where方法

时间:2012-12-17 06:33:36

标签: ruby-on-rails ruby-on-rails-3 arel

我有两个模型 - BannerBannerType

他们的架构如下所示:

广告

# Table name: banners
#
#  id             :integer          not null, primary key
#  name           :string(255)
#  image          :string(255)
#  created_at     :datetime         not null
#  updated_at     :datetime         not null
#  url            :string(255)
#  banner_type_id :integer

BannerType

# Table name: banner_types
#
#  id         :integer          not null, primary key
#  name       :string(255)
#  created_at :datetime         not null
#  updated_at :datetime         not null

Banner belongs_to :banner_typeBannerType has_many :banners

我在BannerType中有两条记录:

BannerType.all
  BannerType Load (0.3ms)  SELECT "banner_types".* FROM "banner_types" 
 => [#<BannerType id: 1, name: "Featured", created_at: "2012-12-17 04:35:24", updated_at: "2012-12-17 04:35:24">, #<BannerType id: 2, name: "Side", created_at: "2012-12-17 04:35:40", updated_at: "2012-12-17 04:35:40">] 

如果我想查询以查找Featured类型的所有横幅,我可以执行以下操作:

Banner.joins(:banner_type).where("banner_types.name = ?", 'Featured')

我知道我也可以通过banner_type_id => 1进行查询,但这与此特定问题密切相关。

如果我们打破这种说法,有些事情对我来说有点混乱。

  1. Banner.join(:banner_type) - 会生成NoMethodError: undefined method 'join' for #<Class:0x007fb6882909f0>当SQL方法名称为什么没有名为join的Rails方法?
  2. 当表名为Banner.joins(:banner_type)时,为什么我会banner_type,即单数banner_types。我没有加入Banner&amp; BannerType表(Rails约定表示为复数)。如果我尝试Banner.joins(:banner_types),这就是我得到的错误:

    Banner.joins(:banner_types) ActiveRecord::ConfigurationError: Association named 'banner_types' was not found; perhaps you misspelled it?

  3. 为什么where子句需要banner_types而不是banner_type(即复数版本 - 即表名而不是joins中使用的符号方法?如果你在两个地方都使用表名,或者在两个地方都使用符号名,那么它会更直观。至少,为了保持一致性。

  4. 为什么我不能通过关联进行动态查找 - 即如果我可以做Banner.find_by_banner_type_name("Featured")会很好?

  5. 很想听听你的想法。

    感谢。

1 个答案:

答案 0 :(得分:9)

#1

  

Banner.join(:banner_type) - 会生成NoMethodError:未定义的方法'join'代表#为什么在SQL方法名称中没有名为join的Rails方法?

当以简单的英语阅读“Banner加入横幅类型”与“横幅加入横幅类型”时更清楚。我不确定是否有更多理由。


#2

  

为什么我在表名为banner_types时执行Banner.joins(:banner_type),即单数banner_type。我没有加入Banner&amp; BannerType表(Rails约定表示为复数)。如果我尝试Banner.joins(:banner_types),这就是我得到的错误:

     

Banner.joins(:banner_types)ActiveRecord :: ConfigurationError:找不到名为'banner_types'的关联;也许你拼错了?

.joins(:banner_type)中,:banner_type是您加入的关系,而不是表格。

has_one :banner_type

这就是Rails加入的内容。当您将符号传递给.joins时,这就是Rails的工作原理,这就是当您传递符号与模型的任何现有关联不匹配时,错误引用关联的原因。

这就是为什么你能够使用嵌套关联的符号来深入JOIN多个级别的原因,如in the Rails Guide所述

Category.joins(:posts => [{:comments => :guest}, :tags])

同样描述in the Rails Guide,您也可以将字符串传递给.joins

Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')

请注意,在最后一个示例中,当String传递给joins时,使用表名 addresses一个关联名称;这有助于回答#3


#3

  

为什么where子句需要banner_types而不是banner_type(即复数版本 - 即表名而不是连接方法中使用的符号?如果你在两个地方都使用表名,那么它会更直观在两个地方使用符号名称。至少,为了保持一致性。

经过一些字符串插值后,传递给where方法的字符串(类似于joins或多或少直接传递到最终的SQL查询 (一路上ARel会有一些操纵)name是一个含糊不清的列(您的bannersbanner_types表都有name列),因此请参阅表格的完整路径[TABLE NAME].[COLUMN NAME]是必需的。例如,如果您在color 中有一些banner_types列(banners 中也不存在),则无需将其用作{{ 1}}在您的"banner_types.color = ?"方法中; where可以正常使用。

注意,就像在#2 中一样,您可以将符号传递给"color = ?"表的where方法。

JOIN

#4

  

为什么我不能通过关联进行动态查找 - 即如果我能做Banner.find_by_banner_type_name(“精选”)会很好吗?

你无法做到这样的发现,因为它在ARel中不受支持,真的很简单(IMO,类似Banner.joins(:banner_type).where(banner_type: [name: 'Featured']) 的方法名称非常令人困惑)