合并三个Active Record数组

时间:2017-02-27 15:16:43

标签: ruby-on-rails heroku activerecord

我试图在Rails 5应用程序中合并三个Active Record数组,以便在我的主页上有一个很好的作业集,论坛帖子和博客。

我有以下代码:

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 %>

我遇到的问题是,此代码不会按created_by按日期顺序显示记录,相反,我有一个相当随机的作业集,论坛帖子和博客看似随意的约会。

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

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

4 个答案:

答案 0 :(得分:2)

function dealPoints(c){
  var nums = Array(6*c).fill().map((_,i) => i+1);
  return nums.reduce(function(r,n,i){
                       var j = i%c;
                       j === 0 && (r.switch = !r.switch);
                       r.switch ? r[j].push(n) : r[c-j-1].push(n);
                       return r;
                     }, Array(c).fill().map(_ => []));
}
var players = 3,
     result = dealPoints(players);

console.log(result);

答案 1 :(得分: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 :如果您仅在某些情况下执行此操作,但是您针对多个模型执行此操作,我希望将其提取到Timestamped模块中(如下所示)。从数据库中提取记录时,您需要在控制器中使用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为ActiveRecord :: Relations定义的most_recent方法相匹配。

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,@ job和@forum_threads变量。 Vivek的答案解决了这个问题,尽管我在控制器中做了扁平化和排序逻辑:

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 %>

确保您的部分名称正确

答案 2 :(得分: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 %>

答案 3 :(得分:0)

如果我正确理解了您的问题,您希望在按日期合并后对数组进行排序。我会那样做:

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

希望有所帮助。