2016-07-01 1 views
1

私が取り組んでいるrails-apiでは、現在実行中の呼び出しを最適化しようとしていますが、.includes機能に問題があります。私はそれがほとんどの状況で動作しているが、それが私がそれをしたい方法で動作していない1つの特定の状況があります。ここでレールにモデルメソッドで使用されていないキャッシュが含まれています

は例です:

Userクラス

class User < ActiveRecord::Base 
    has_many :images 
    has_one :active_image, -> { where(images: { active_image: true })}, class_name: 'Image' 
    has_many :facebook_auth 

    def get_profile_image 
    if active_image 
     active_image.image.url(:profile) 
    else 
     facebook = facebook_auth.last 
     if facebook 
     "https://graph.facebook.com/#{facebook.provider_user_id}/picture?width=150&height=150" 
     end 
    end 
    nil 
    end 
end 

コントローラー:これにより

class UserController < BaseAPIController 
    def get_user_image 
    user_id = params[:user_id] 
    user = User.includes(:active_image, :facebook_auth).find(user_id) 
    render json: user.get_profile_image 
    end 
end 

、私はそれらを呼び出すときよう.includes(:active_image, :facebook_auth)がデータをキャッシュすることを前提としますget_profile_imageメソッドを呼び出すと、dbコールはそれ以上作成されませんが、そうではありません。私はここで間違って何をしていますか?

おかげで、 チャーリー

+0

active_imageも含める必要があります –

+0

ああ、ちょうどタイプミスです。私の実際のコードでは、私はそれをやっています。私はそれを修正します。 –

+0

'render json:user.get_profile_image'のタイプミスも' render json:user.get_profile_images'です – neydroid

答えて

1

ほとんどどこにいるのですか? このアプローチしてみてください。

# for one user, with id 2: 
User.eager_load_image_data.find(2).profile_image_url 

# for a collection (using 'all' here): 
User.eager_load_image_data.all.map{ |user| 
    [user.name, user.profile_image_url] 
} 

画像データがeagerloadedされる。この方法で、画像クラスとから両方:あなたのコントローラに続いて

class User < ApplicationRecord 
    has_many :images, dependent: :destroy 
    has_one :active_image, 
    -> { where(active: true) }, 
    class_name: 'Image' 

    has_many :facebook_auths, dependent: :destroy 
    has_one :active_facebook_auth, 
    -> { order("created_at desc") }, 
    class_name: 'FacebookAuth' 

    scope :eager_load_image_data, 
    -> { includes(:active_image).includes(:active_facebook_auth) } 

    def profile_image_url 
    if active_image 
     active_image.url 
    elsif active_facebook_auth 
     "https://graph.facebook.com/#{active_facebook_auth.provider_user_id}/picture?width=150&height=150" 
    else 
     nil 
    end 
    end 
end 

をか、熱心な負荷イメージにしたい時はいつでもFacebookAuthクラス。

も私が固定しているあなたの方法 ユーザ#のget_profile_imageで他のいくつかの問題が

:それは常にnilを返し

  • 。私はあなたの本当のコードであなたが早期返品をしていると確信しています。
  • コレクションの場合は、facebook_auth_tokensを検索するとN + 1のクエリを行います。
+0

これは良いchipaironに見えます、私は先に進み、これを試して、それがどのように動作するか見てみましょう。ありがとう! –

+0

さて、私は100%確信しているわけではありませんが、これはうまくいきます!私は問題は私がhas_manyをやっていたことだと思って、その上で.lastのようなことをやろうとしていて、それらを追加することによって全く新しいクエリができました。 has_manyの代わりにorder descとhas_oneを追加することは、私が思うように修正したものです。ありがとう! –

0

まあ、私はコメントしたかったが、コメントにコードを置くことができませんでしたので、私は非答えを与えている...

私が表示されません明らかに何か問題が、回避策として、あなたはこのユーザーまたはどこかに行うことができます:

def self.user_profile_image(user_id) 
    active_image = Images.where(user_id: user_id).where(active_image: true).first 

    if active_image 
     active_image.image.url(:profile) 
    else 
    facebook = FaceBookAuth.where(user_id: user_id).last 
    if facebook 
     "https://graph.facebook.com/#{facebook.provider_user_id}/picture?width=150&height=150" 
    end 
    end 

    nil 
end 

そして、ちょうどそれが過度に単純化しない場合は、お使いのコントローラで画像をキャッシュ/呼び出し...

を3210
def get_user_image 
    render json: User.user_profile_image(params[:user_id]) 
end 

これは、2つの比較的効率的なクエリを作成します。ユーザーなどが不必要に読み込まれることはありません。

+0

私は例として上記のコードを使用しています。私の実際のコードでは、はるかに複雑で、私はユーザーデータを使用しています。実際にはループしているので、インクルードが機能することが重要です。 –

+0

ああ。私はそれが事実かもしれないと思った。もう1つの回避策は、イメージを1つのクエリでプリフェッチし、ハッシュテーブルに保持することです。その後、ユーザーやその他の人がループしている間に、たくさんのクエリを実行するのではなく、簡単なO(1)検索を実行して画像を取得できます。基本的には、プリフェッチが行うべきことを手動で行うでしょう。 –

+0

これは実際に私たちが使用している回避策です。しかし、無関係のインスタンス変数を使用しなければならないし、余分なループを避けようとしている。私はそれが動作するようにする方法がなければならないと確信しているので、私はどこに間違っているのか見たいと思っています。 –

関連する問題