我有两个模型 - Banner
和BannerType
。
他们的架构如下所示:
广告
# 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_type
和BannerType 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
进行查询,但这与此特定问题密切相关。
如果我们打破这种说法,有些事情对我来说有点混乱。
Banner.join(:banner_type)
- 会生成NoMethodError: undefined method 'join' for #<Class:0x007fb6882909f0>
当SQL方法名称为什么没有名为join
的Rails方法?当表名为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?
为什么where
子句需要banner_types
而不是banner_type
(即复数版本 - 即表名而不是joins
中使用的符号方法?如果你在两个地方都使用表名,或者在两个地方都使用符号名,那么它会更直观。至少,为了保持一致性。
为什么我不能通过关联进行动态查找 - 即如果我可以做Banner.find_by_banner_type_name("Featured")
会很好?
很想听听你的想法。
感谢。
答案 0 :(得分:9)
Banner.join(:banner_type) - 会生成NoMethodError:未定义的方法'join'代表#为什么在SQL方法名称中没有名为join的Rails方法?
当以简单的英语阅读“Banner加入横幅类型”与“横幅加入横幅类型”时更清楚。我不确定是否有更多理由。
为什么我在表名为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 。
为什么where子句需要banner_types而不是banner_type(即复数版本 - 即表名而不是连接方法中使用的符号?如果你在两个地方都使用表名,那么它会更直观在两个地方使用符号名称。至少,为了保持一致性。
经过一些字符串插值后,传递给where
方法的字符串(类似于joins
)或多或少直接传递到最终的SQL查询 (一路上ARel会有一些操纵)。 name
是一个含糊不清的列(您的banners
和banner_types
表都有name
列),因此请参阅表格的完整路径[TABLE NAME].[COLUMN NAME]
是必需的。例如,如果您在color
中有一些banner_types
列(banners
中也不存在),则无需将其用作{{ 1}}在您的"banner_types.color = ?"
方法中; where
可以正常使用。
注意,就像在#2 中一样,您可以将符号传递给"color = ?"
表的where
方法。
JOIN
为什么我不能通过关联进行动态查找 - 即如果我能做Banner.find_by_banner_type_name(“精选”)会很好吗?
你无法做到这样的发现,因为它在ARel中不受支持,真的很简单(IMO,类似Banner.joins(:banner_type).where(banner_type: [name: 'Featured'])
的方法名称非常令人困惑)。