Rails:在控制器

时间:2015-12-09 01:28:05

标签: ruby-on-rails ajax

我希望我能清楚地解释清楚。

  • 用户有很多通知和有很多电影 通知。电影has_many预告片。

  • 通知有3列:user_id,movie_id和网站。

  • 在预告片#index上,我正在呈现@trailers并且每个@trailer呈现 3 x ajax notification_forms(每个表单只是一个按钮,一个用于 每个"网站"选项。当用户单击此按钮时,将发送ajax请求以创建新的通知记录)

  • 我会跟踪哪些按钮被按下(通过查看是否存在该用户/电影的通知)

我担心的是因为我只预加载@trailers,我现在正在预告片的每次迭代中进行3次新的DB调用。

_notification_form.html.erb(每个预告片被调用3次)

<% if trailer.movie.tracked?(current_user, "netflix") %>
   ## do some css stuff on the button to show notification already set

movie.rb:

def tracked?(user, website)
    user.notifications.where(movie_id: self.id, website: website).first
  end

因此每次呈现预告片部分时,我都会进行3次DB调用。处理这种情况的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

由于您只检查current_user的状态,并且每个Trailer都知道其movie_id,因此您只需加载User&#39} Notification并检查Trailer s&#39; movie_id S:

tracked = current_user.notifications
tracked.detect { |n| n.movie_id == trailer.movie_id && n.website == 'netflix' }

如果User可能 Notification,您可以将Notification s的设置限制为Trailer秒在您要显示的页面上:

tracked = current_user.notifications.where(movie_id: trailers.map(&:movie_id))

将其加载,然后在决定如何渲染按钮时进行检查。您可以通过创建包含Set对的[movie_id, website]来提高效率,这将在固定时间内进行查找。

tracked = Set.new(
  current_user.nofications
    .where(movie_id: trailers.map(&:movie_id))
    .pluck(:movie_id, :website)
)
tracked.include?([trailer.movie_id, 'netflix'])

此策略对您来说很快,因为它完全适合您要检查的数据。如果您需要更灵活的东西,仍然可以最大限度地减少数据库查询,请考虑加入与includespreloadeager_load的关联。 3 ways to do eager loading (preloading) in Rails 3 & 4对这些方法之间的差异有很好的描述。这些都在你最初的关系加载过程中起作用(也就是说,如果你还没有加载任何东西),但是当你已经加载了部分数据时(例如,你有Trailer但没有MoviesNotification s),您可以使用ActiveRecord::Associations::Preloader有效加载其余内容。