12

と の 2 つのモデルが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

バナータイプ

# 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 には次の 2 つのレコードがあります。

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_typebanner_types. Banner & 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")ですか?

ご意見をお待ちしております。

ありがとう。

4

1 に答える 1

9

#1

Banner.join(:banner_type) - NoMethodError: undefined method 'join' for を生成します

「Banner Joins banner type」対「Banner join banner type」という平易な英語として読むと、より明確になります。それ以上の理由があるかどうかはわかりません。


#2

テーブル名が banner_types の場合、Banner.joins(: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 を渡すと、エラーが関連付けを参照する理由です。

これは、Rails ガイドでJOIN説明されているように、ネストされた関連付けのシンボルを使用して の複数レベルの深さを実行できる理由でもあります。

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

Rails Guideにも記載されているように、 Strings を渡すこともでき.joinsます。

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

この最後の例では、文字列が に渡されるときにjoins、関連付け名ではなくテーブル名 addressesが使用されることに注意してください。これは答え#3に役立ちます。


#3

なぜ where 節は banner_type ではなく、banner_types を必要とするのですか (つまり、複数形のバージョン - つまり、joins メソッドで使用される記号ではなく、テーブル名が必要なのですか?両方の場所でテーブル名を使用するか、記号を使用すると、より直感的になるようです。少なくとも、一貫性の目的で、両方の場所に名前を付けます。

少し文字列を補間した後、whereメソッドに渡された文字列(同様joins)は最終的な SQL クエリに多かれ少なかれ直接渡されます(途中で ARel による操作が少しあります)nameはあいまいな列です(テーブルテーブルの両方に列があります)bannersbanner_typesnameため、フル パスでテーブルを参照する[TABLE NAME].[COLUMN NAME]必要があります。たとえば、( にも存在しなかった)colorにいくつかの列があった場合、メソッドのようにそれを使用する必要はありません。うまくいきます。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 に答える