2017-02-27 92 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