这是现有应用程序的优化问题,我已经使代码通用,既使其变得更加容易理解,也更容易理解,而不是我描述论坛讨论类型情况的专有模型。我已修改此示例中的所有代码而未对其进行测试,因此如果有任何错别字我道歉,如果有人向我指出,我会尝试修复它们。
让我们说我有一个有四个模型的rails应用程序:Event,User,Forum和Post。
重要的关系如下:
前端是单页javascript应用程序,因此所有数据库数据都需要以json格式返回。
背景:
example.com/forum/15/all_posts
见下相关代码:
论坛管制员:
#forums_controller.rb
def all_posts
current_user = User.find(session[:user_id])
forum = Forum.includes(:posts).where(id: params[:id]).take
forum.posts.each do |post|
post.current_user = current_user
end
render json: forum.to_json(
include: [
{ posts: {
methods: [:is_new]
}}
]
)
end
帖子模特:
#post.rb (posts model)
has_many :events
attr_accessor :current_user
def is_new
if current_user #user may not be logged in
!!self.events.where(user_id: current_user.id, name: 'Show').take
else
false
end
end
模型是动作所在的位置,因此我们尝试将逻辑排除在控制器之外,但由于会话在模型中不可用,我们最终将这个疯狂的工作添加为将current_user添加为attr_accessor,以便方法可以为相关用户返回适当的数据....我不喜欢这样,但我从来没有想出更好的方法来做到这一点。我们在其他地方重复了这种模式,我很乐意听到替代方案。
这是我的问题:
在前端使用is_new调用来确定哪些帖子可以点亮,但它也会触发n + 1场景如果有10个帖子,这个端点会给我带来总共12个查询如果我的活动表很大,那就不好了。如果我将所有逻辑移动到控制器,我可以在2个查询中执行此操作。
总之,我有两个问题:答案 0 :(得分:1)
如果使用scope
是一种选择,我会尝试类似:
class Post < ApplicationRecord
scope :is_new, -> { where(user_id: current_user.id, name: 'Show') } if current_user.id?
end
如果在您的情况下发送current_user
是更好的选择,您也可以这样做:
class Post < ApplicationRecord
scope :is_new, ->(current_user) {...}
end
答案 1 :(得分:0)
这只是一个伪代码来举例:
当我发布这个时,我忘了你正在从ForumsController渲染json。
scope :for_user, -> (user = nil) do
includes(events: :users).where(users: {id: user.id}) if user
end
def is_new_for_user?(user = nil)
return true if user.nil?
self.events.empty?{ |e| e.name == 'Show' }
end
def index
@posts = Post.for_user(current_user)
end
...
<% if post.is_new_for_user?(current_user) %>
...
<% end
...
这仍然是伪代码。我没有测试任何东西。
scope :for_user, -> (user = nil) do
if user
includes(posts: [events: :users]).where(users: {id: user.id})
else
includes(:posts)
end
end
def all_posts
current_user = User.find(session[:user_id])
forum = Forum.for_user(current_user).where(id: params[:id]).take
render json: forum.to_json(
include: [
{ posts: {
methods: [:is_new_for_user?(current_user)]
}}
]
)
end