12

我有两个模型 -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

横幅类型

# 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)- 会生成为什么当那是 SQL 方法名称时NoMethodError: undefined method 'join' for #<Class:0x007fb6882909f0>没有调用 Rails 方法?join
  2. 当表名Banner.joins(:banner_type)是. 我没有加入 Banner 和 BannerType 表(Rails 约定表示为复数)。如果我尝试这是我得到的错误:banner_typebanner_typesBanner.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")

很想听听你的想法。

谢谢。

4

1 回答 1

9

#1

Banner.join(:banner_type) - 会生成 NoMethodError: undefined method 'join' for # 为什么没有 Rails 方法调用 join 而那是 SQL 方法名?

用简单的英语阅读时说“横幅加入横幅类型”与“横幅加入横幅类型”会更清楚。我不确定还有更多的原因。


#2

为什么我做Banner.joins(:banner_type) 即当表名是banner_types 时单数banner_type。我没有加入 Banner 和 BannerType 表(Rails 约定表示为复数)。如果我尝试 Banner.joins(:banner_types) 这是我得到的错误:

Banner.joins(:banner_types) A​​ctiveRecord::ConfigurationError: 未找到名为“banner_types”的关联;也许你拼错了?

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

has_one :banner_type

这就是 Rails 加入的原因。这就是当您将 Symbol 传递给 时 Rails 的工作原理,这.joins就是为什么当您传递与模型的任何现有关联不匹配的 Symbol 时错误指的是关联。

这也是为什么你可以JOIN使用嵌套关联的符号来做多层深度,如Rails Guide 中所述

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

在 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(即复数版本-即表名而不是joins方法中使用的符号?如果您在两个地方都使用表名或使用符号似乎会更直观两个地方都有名字。至少,为了保持一致。

经过一点字符串插值后,传递给where方法的字符串(类似于joins或多或少直接传递到最终的 SQL 查询中(一路上会有一点 ARel 的操作)name是一个模棱两可的列(你的bannersbanner_types表都有一个name列),所以需要通过它的完整路径来引用表[TABLE NAME].[COLUMN NAME]。例如,如果您有一些color列 in banner_types (该列也不存在于banners)中,则无需像"banner_types.color = ?"在您的where方法中那样使用它;"color = ?"会工作得很好。

请注意,就像在#2中一样,您可以将符号传递给'd 表的where方法。JOIN

Banner.joins(:banner_type).where(banner_type: [name: 'Featured'])

#4

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

你不能做这样的查找,因为 ARel 不支持它,它真的很简单(IMO,一个方法名称find_by_banner_type_name很混乱)

于 2012-12-17T07:03:23.140 回答