2017-02-27 88 views
1

我想在Rails 5应用程序中合并三个活动记录数组,以便在主页上有很好的作业集合,论坛主题和博客。合并三个活动记录数组

我有以下代码:

application_controller.rb

def home 
    @blogs = Blog.limit(6) 
    @jobs = Job.where(approved: true).limit(6) 
    @forum_threads = ForumThread.includes(:forum_posts).limit(6) 
    @everything = @blogs + @jobs + @forum_threads 
end 

home.html.erb

<% @everything.sort_by(&:created_at).reverse.each do |item| %> 
    <% if item.is_a?(Job) %> 
     <%= render partial: "application/partials/home_job", locals: {item: item} %> 
    <% elsif item.is_a?(ForumThread) %> 
     <%= render partial: "application/partials/home_forum", locals: {item: item} %> 
    <% elsif item.is_a?(Blog) %> 
     <%= render partial: "application/partials/home_blog", locals: {item: item} %> 
    <% end %> 
<% end %> 

我遇到的问题是,这个代码不被显示在日期顺序记录相反,我有一个相当随机的工作集合,论坛主题和博客,从一个看似随机的日期开始。

如果我添加一个新工作,它不会出现在显示在/home页面上的集合中。但是,如果我从数据库中删除所有记录并开始添加新记录,那么代码将正常工作,并按照我期望的行为以正确的顺序显示帖子。

我无法将此代码直接推送到Heroku,因为我无法删除生产中已存在的所有记录。这几乎就像需要清除某种缓存。有谁知道发生了什么事?

回答

2
@blogs = Blog.order(created_at: :desc).limit(6) 

+0

原则上好。我建议'Blog.order(created_at::desc).limit(6)',否则限制在订单和最新可能不包括在内。 – SteveTurczyn

+0

如果我这样做,那么三个不同的集合被分组在一起。因此,所有的博客文章彼此相邻,彼此相邻的工作......我希望他们都混合在一起,并按created_by排序 – BillyBib

+0

不,您仍然可以执行@everything然后执行'sort_by' ... @KcUS_unico答案只是确保您首先获得正确的记录。 – SteveTurczyn

0

你可以这样做:

def home 
    @collections=[] 
    @collections << Blog.limit(6) 
    @collections << Job.where(approved: true).limit(6) 
    @collections << ForumThread.includes(:forum_posts).limit(6) 
end 

<% @collections.flatten.sort_by(&:created_at).reverse.each do |item| %> 

....iteration here .... 

<% end %> 
0

如果我理解你的问题正确,你想你按日期合并后的数组进行排序。我会这样做:

@everything = @everything.sort {|x| x.created_at } 

希望有所帮助。

1

问题1:得到正确的记录从数据库

选项A:如果你将永远是排序由created_at值(一个共同的愿望),每个模型,default_scope添加到每个模型( Rails 4+以下版本)。您在控制器中的限制呼叫将自动利用默认范围。

app/models/blog.rb

class Blog < ActiveRecord::Base 
    default_scope { order created_at: :desc } 
    ... 
end 

选项B:如果你只能这样做在某些情况下,但你的几款机型做了,我想提取到一个时间戳的模块(如下图)。从数据库提取记录时,您需要在控制器中使用most_recent方法,以确保获得最新的记录。

app/models/concerns/timestamped.rb

module Timestamped 
    extend ActiveSupport::Concern 

    included do 
    scope :most_recent, -> { order created_at: :desc } 
    scope :least_recent, -> { order created_at: :asc } 
    scope :most_fresh, -> { order updated_at: :desc } 
    scope :least_fresh, -> { order updated_at: :asc } 
    end 
end 

class Blog < ActiveRecord::Base 
    include Timestamped 
    ... 
end 

问题2:排序阵列

即使有一个简单的情况下是这样,我建议补充说的是timestamped.rb定义most_recent方法相匹配的阵列延伸为ActiveRecord ::关系。

lib/array_extensions.rb

class Array 
    def most_recent 
    sort { |a, b| b.created_at <=> a.created_at } 
    end 
end 

,然后需要与一个初始化扩展:

config/initializers/extensions.rb

require 'array_extensions' 

问题3:保持在控制器的清洁。

通常,每个控制器操作应该只设置一个实例变量,在这种情况下,它看起来像甚至没有在视图中使用@blogs,@jobs和@forum_threads变量。维韦克的回答解决了这一点,虽然我做的控制器扁平化及排序逻辑:

def home 
    @posts = Blog.most_recent.limit(6) + Job.approved.most_recent.limit(6) + ForumThread.most_recent.includes(:forum_posts).limit(6) 
    @posts = @posts.most_recent 
end 

问题4:在你看来最小化的if/then逻辑

取而代之的是:

<% @everything.sort_by(&:created_at).reverse.each do |item| %> 
    <% if item.is_a?(Job) %> 
    <%= render partial: "application/partials/home_job", locals: {item: item} %> 
    <% elsif item.is_a?(ForumThread) %> 
    <%= render partial: "application/partials/home_forum", locals: {item: item} %> 
    <% elsif item.is_a?(Blog) %> 
    <%= render partial: "application/partials/home_blog", locals: {item: item} %> 
    <% end %> 
<% end %> 

这样做:

<% @everything.sort_by(&:created_at).reverse.each do |item| %> 
    <%= render "application/partials/home_#{item.class.name.underscore}", item: item %> 
<% end %> 

而且确保你的部分命名适当

+0

非常感谢。现在我要使用Option A,但我只是重构我的代码来清理控制器,并避免在视图中使用if/else语句。我甚至不知道你可以做''application/partials/home _#{item.class.name.underscore}“'所以谢谢你教我新东西 – BillyBib

+0

很高兴这对你有帮助! – Trip