2983


PublicActivityのgemを使ってるのですが、activitiesを取得する時にパフォーマンス改善のために出来るだけまとめてSQLで取ってくるようにしたいです。

[code]

    PublicActivity::Activity.includes(trackable: [:post]).where(trackable_type: ['Like', 'Comment'])
    
[/code]

そこで上記のようにtrackableとその先のpostまでincludesすることによってパフォーマンスは改善したのですが、`post`レコードが存在しない時(削除した時など)に、

`Association named 'post' was not found`というエラーが出ます。

`joins`を使えば、存在するレコードだけ取ってくる、と聞いて使おうとすると今度は `Cannot eagerly load the
polymorphic association`というエラーが出ます。

何か良い解決方法はありますでしょうか?

関連するモデルの情報が抜けておりました。追記致します。

Postモデル

[code]

    Class Post < ActiveRecord::Base
      has_many :comments
    
[/code]

Commentモデル

[code]

    Class Comment < ActiveRecord::Base
      include PublicActivity::Common 
      belongs_to :post
      has_many :likes
    
[/code]

Likeモデル

[code]

    Class Like < ActiveRecord::Base
      include PublicActivity::Common 
      belongs_to :comment
    
[/code]

となっています。


CC BY-SA 3.0
2014-12-30T10:49:39.930
2832
2015-01-15T14:57:28.623
2015-01-15T14:57:28.623
4978
859
question
ruby-on-rails rails-activerecord
includesしたモデルが持つレコードが存在しない場合の対処について


「ネットで検索したらそれっぽい情報が見つかった」というレベルですが、こちらのページが参考になるかもしれません。  
一度チェックしてみてください。

<https://stackoverflow.com/questions/20701770/in-rails-how-to-eager-load-an-
association-only-if-the-association-is-not-nil>

ちなみに、「activitiesを取得する時にパフォーマンス改善のために出来るだけまとめてSQLで取ってくる」というのは **eager loading**
と呼ばれるテクニック（？）なので、"PublicActivity eager load"というキーワードで検索してみました。

こうすると英語のページがたくさん引っかかると思うので、見つかったページを調べていくと答えが見つかるかもしれません。

こちらもご参考までに。


CC BY-SA 3.0
2014-12-31T22:56:41.673
2877
2014-12-31T22:56:41.673
2017-05-23T12:38:56.083
-1
85
2832
answer


`includes` を使ったクエリを手元で試したところ、`Like` に `post`
という名前のアソシエーションは無い、というエラーメッセージになりました (Postレコードは削除していない状態でです):

> ActiveRecord::AssociationNotFoundError: Association named 'post' was not
> found on Like; perhaps you misspelled it?

この場合、`post` アソシエーションを `Like` に追加することで通るようになります:

[code]

    class Like < ActiveRecord::Base
        include PublicActivity::Common
        belongs_to :comment
        has_one :post, :through => :comment
    end
    
[/code]

コンソール上で、発行されるクエリを確認:

[code]

    > post = Post.new
    > post.save
    > post.comments << Comment.new
    > comment = Comment.first
    > comment.likes << Like.new
    > like = Like.first
    > like.create_activity key: 'like.create'
    > PublicActivity::Activity.includes(trackable: [:post]).where(trackable_type: ['Like', 'Comment'])
      PublicActivity::Activity Load (0.3ms)  SELECT "activities".* FROM "activities"  WHERE "activities"."trackable_type" IN ('Like', 'Comment')
      Like Load (0.1ms)  SELECT "likes".* FROM "likes"  WHERE "likes"."id" IN (1)
      Comment Load (0.2ms)  SELECT "comments".* FROM "comments"  WHERE "comments"."id" IN (1)
      Post Load (0.1ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."id" IN (1)
     => #<ActiveRecord::Relation [#<PublicActivity::Activity id: 2, ...>]> 
    
[/code]

なぜエラーになっていたか:

問題のクエリで、`Activity.trackable` に入ってくるのは `Like` または `Comment` モデルです:

[code]

    PublicActivity::Activity.includes(trackable: [:post]).where(trackable_type: ['Like', 'Comment'])
    
[/code]

`trackable: [:post]` は、 `Like` または `Comment` に定義されている `post`
アソシエーションを取ってこい、と言っていることになります。エラーになっていたのは、`Like` には `post` アソシエーションが無かったためです。

Rails にあまり詳しくないので、もっとクエリを減らす方法はあるかもしれません。


CC BY-SA 3.0
2015-01-03T12:03:49.510
2983
2015-01-03T12:03:49.510
30
2832
answer