我怎样才能像下面一样使用模型和控制器而不是视图获取记录?
Pattern1。与辅助
application_helper
def user_link(username)
link_to User.find_by_username(username).user_profile.nickname, show_user_path(username)
end
视图<% @topics.order("updated_at DESC").limit(100).each do |topic| %>
<%= user_link(topic.comment_threads.order("id").last.user.username) if topic.comment_threads.present? %>
<% end %>
Pattern2。没有帮手。仅查看
<% @topics.order("updated_at DESC").limit(100).each do |topic| %>
<%= link_to(topic.comment_threads.order("id").last.user.nickname, show_user_path(topic.comment_threads.order("id").last.user.username) ) if topic.comment_threads.present? %>
<% end %>
<% @community.topics.eager.recent.each do |topic| %>
<%= user_link(topic.comment_threads.order("id").last.user.username) if topic.comment_threads.present? %>
<% end %>
SQL代码或SQL生成器永远不应该到达视图层。这应该在你的模型中。我甚至不会在控制器中放置这样的查询。
我将topic
SQL构建器提取到命名作用域。最重要的是,为了避免n+1查询,我将创建另一个命名范围eager
:
# topic.rb
scope :eager, includes(comment_threads: :user)
scope :recent, lambda { |n = 100| order("updated_at DESC").limit(n) }
然后我将comment_threads
SQL构建器移动到您的comment_threads模型:
# comment_thread.rb
def self.last_user_nickname
order("id").last.user.nickname
end
我们现在可以整理您的视图:
<% @topics.eager.recent.each do |topic| %>
<%= user_link(topic.comment_threads.last_user_nickname) if topic.comment_threads.present? %>
<% end %>
允许我把Slim卖给你(动词替代):
- @topics.eager.recent.each do |topic|
= user_link(topic.comment_threads.last_user_nickname) if topic.comment_threads.present?
我甚至可以更进一步,将user_link
提取成UserDecorator
。详见https://github.com/drapergem/draper
- 将
topic
的SQL builder提取到topic
下的eager
和recent
作用域 - 提取
comment_threads
的SQL builder到comment_thread
下的last_user_nickname
- 考虑将
user_link
提取为UserDecorator
- 使用苗条!:)