1

Rails 3 アプリで異常な状況を発見しました。

次のモデルを検討してください。

class Genre < ActiveRecord::Base
  has_many :banner_genres, :dependent => :destroy
  has_many :banners, :through => :banner_genres
  ...

class BannerGenre < ActiveRecord::Base
  attr_accessible :banner_id, :banner, :genre_id, :genre, :position

  belongs_to :genre
  belongs_to :banner
  ...

class Banner < ActiveRecord::Base
  has_many :banner_genres, :dependent => :destroy
  has_many :genres, :through => :banner_genres
  ...

バナーのあるジャンルがある場合、Rails コンソールに次の行が表示されます。

1.9.3p362 :005 > g = Genre.find 62
  Genre Load (0.8ms)  SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT 1  [["id", 62]]
 => #<Genre id: 62, ...

1.9.3p362 :006 > g.banner_genres.any?
   (0.5ms)  SELECT COUNT(*) FROM "banner_genres" WHERE "banner_genres"."genre_id" = 62
 => true 

1.9.3p362 :007 > g.banners
  Banner Load (1.0ms)  SELECT "banners".* FROM "banners" INNER JOIN "banner_genres" ON "banners"."id" = "banner_genres"."banner_id" WHERE "banner_genres"."genre_id" = 62 ORDER BY position
 => [#<Banner id: 446, ...

1.9.3p362 :008 > g.banners.any?
 => false 

なぜ.any?返品するのfalseですか?同じプロジェクトの関連付けを通じて別の has_many を使用すると、 が返されますtrue

編集:

ここでコードを渡すときにタイプミスがありました。has_many の banner_genres です。ジャンル_バナーではありません。

また、逆関連付けは想定どおりに機能します。

1.9.3p362 :004 > b = Banner.find 446
  Banner Load (1.1ms)  SELECT "banners".* FROM "banners" WHERE "banners"."id" = $1 ORDER BY position LIMIT 1  [["id", 446]]
 => #<Banner id: 446...

1.9.3p362 :005 > b.genres.any?
 (0.8ms)  SELECT COUNT(*) FROM "genres" INNER JOIN "banner_genres" ON "genres"."id" = "banner_genres"."genre_id" WHERE "banner_genres"."banner_id" = 446
 => true 

編集 2

さらに奇妙なコンソール出力:

1.9.3p362 :007 > g.banners.class
 => Array 
1.9.3p362 :008 > g.banners.any?
 => false 
1.9.3p362 :004 > g.banners.any? {|b| b}
 => true 
1.9.3p362 :006 > g.banners.count
 (0.9ms)  SELECT COUNT(*) FROM "banners" INNER JOIN "banner_genres" ON "banners"."id" = "banner_genres"."banner_id" WHERE "banner_genres"."genre_id" = 62
 => 1 
1.9.3p362 :009 > g.banners.to_a.any?
 => true 

編集 3

g.banner_genres
  BannerGenre Load (0.7ms)  SELECT "banner_genres".* FROM "banner_genres" WHERE "banner_genres"."genre_id" = 62
 => [#<BannerGenre id: 4, genre_id: 62, banner_id: 446, position: 1, created_at: "2013-03-15 16:41:10", updated_at: "2013-03-15 16:41:10">]

編集 4 Aleks からの質問

g.banners.any に表示されるクエリを表示していただけますか? そしてg.banners。 それはまったく同じクエリですが、さらに奇妙です。私もオーバーライドしませんでしたか?メソッドはどこでも。

1.9.3p362 :037 > g.banners(true)
  Banner Load (1.0ms)  SELECT "banners".* FROM "banners" INNER JOIN "banner_genres" ON "banners"."id" = "banner_genres"."banner_id" WHERE "banner_genres"."genre_id" = 62 ORDER BY position
 => [#<Banner id: 446, ...
1.9.3p362 :038 > g.banners(true).any?
  Banner Load (1.2ms)  SELECT "banners".* FROM "banners" INNER JOIN "banner_genres" ON "banners"."id" = "banner_genres"."banner_id" WHERE "banner_genres"."genre_id" = 62 ORDER BY position
 => false 

1.9.3p362 :039 > g.banners.method(:any?)
 => #<Method: Array(Enumerable)#any?> 
4

2 に答える 2

1

any?戻ってくるはずだったtrue....私はこの問題にとても興味があったので、シミュレートすることにしました。

g = Genre.find 1
Genre Load (30.1ms)  SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT 1  [["id", 1]]
=> #<Genre id: 1, name: "a", created_at: "2013-03-19 11:44:32", updated_at: "2013-03-19 11:44:32"> 

g.banner_genres.any?
(0.3ms)  SELECT COUNT(*) FROM "banner_genres" WHERE "banner_genres"."genre_id" = 1
=> true 

g.banners
Banner Load (0.5ms)  SELECT "banners".* FROM "banners" INNER JOIN "banner_genres" ON "banners"."id" = "banner_genres"."banner_id" WHERE "banner_genres"."genre_id" = 1
=> [#<Banner id: 1, name: "1", created_at: "2013-03-19 11:43:00", updated_at: "2013-03-19 11:43:00">, #<Banner id: 2, name: "2", created_at: "2013-03-19 11:43:59", updated_at: "2013-03-19 11:43:59">] 

g.banners.any?
=> true 

また、

g.banners.class
=> Array 
g.banners.any?
=> true 
g.banners.to_a.any?
=> true 

コードで何か他のことが起こっています...

于 2013-03-19T11:58:23.657 に答える
1

ここでの本当の問題は、関連付けが良いか悪いかではなく、false要素を含む配列に対して表示される理由です。値を返していることは明らかですが、問題はなぜそれが返されているのかですfalse

説明はここにあるかもしれません: Ruby の #any を取得できませんか? nil オブジェクトのリストで false を返す

がどのようにany?実装されているか、質問とどのように関連しているかを確認すると、ヒントが得られる場合があります。

このリンクも参照してください: http://apidock.com/ruby/Enumerable/any%3F

編集:

あなたが言っていること: まず、 の配列がありobjectsます。どちらがany?戻ってきますかfalse

しかし、あなたがそうするなら、あなたは.to_a次のようなことをします:

Time.new.to_a   #=> [39, 54, 8, 9, 4, 2013, 3, 99, true, "CET"]

truenullではないオブジェクトがあるため、それが を返す理由です。

編集2

注意:any?配列falseのすべてのオブジェクトがnilまたはfalse

于 2013-03-19T11:14:13.270 に答える