Rails 包括未在模型方法中使用的缓存
Rails includes cache not being used in model method
因此,在我正在处理的 rails-api 中,我们目前正在尝试优化一些较长的 运行 调用,但我遇到了问题使用 .includes 功能。我在大多数情况下都能正常工作,但在一种特殊情况下它无法按照我想要的方式工作。
这是一个例子:
用户class
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 方法中调用它们时,它不会再进行任何数据库调用,但这是是这样的。我在这里做错了什么?
谢谢,
查理
好吧,我想发表评论,但无法将代码放入评论中,所以我给出了一个非答案...
我没有发现任何明显的错误,但作为解决方法,您可以在 User 或其他地方执行此操作:
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
只要 call/cache 控制器中的图像,如果这不是过于简单的话...
def get_user_image
render json: User.user_profile_image(params[:user_id])
end
这最多使 2 个相对有效的查询成为可能。它不会不必要地加载用户等
你快到了!
试试这个方法:
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
然后在您的控制器中或任何您想要加载图像的时候:
# 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]
}
通过这种方式,可以从 Image class 和 FacebookAuth class 中预先加载图像数据.
你的方法 User#get_profile_image 中还有一些其他问题,我已修复:
- 它总是 returns 零。我确信在你的真实代码中你早 returns.
- 对于集合,如果要查找 facebook_auth_tokens,它会进行 N+1 查询。
因此,在我正在处理的 rails-api 中,我们目前正在尝试优化一些较长的 运行 调用,但我遇到了问题使用 .includes 功能。我在大多数情况下都能正常工作,但在一种特殊情况下它无法按照我想要的方式工作。
这是一个例子:
用户class
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 方法中调用它们时,它不会再进行任何数据库调用,但这是是这样的。我在这里做错了什么?
谢谢, 查理
好吧,我想发表评论,但无法将代码放入评论中,所以我给出了一个非答案...
我没有发现任何明显的错误,但作为解决方法,您可以在 User 或其他地方执行此操作:
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
只要 call/cache 控制器中的图像,如果这不是过于简单的话...
def get_user_image
render json: User.user_profile_image(params[:user_id])
end
这最多使 2 个相对有效的查询成为可能。它不会不必要地加载用户等
你快到了! 试试这个方法:
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
然后在您的控制器中或任何您想要加载图像的时候:
# 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]
}
通过这种方式,可以从 Image class 和 FacebookAuth class 中预先加载图像数据.
你的方法 User#get_profile_image 中还有一些其他问题,我已修复:
- 它总是 returns 零。我确信在你的真实代码中你早 returns.
- 对于集合,如果要查找 facebook_auth_tokens,它会进行 N+1 查询。