2017-02-27 11 views
1

私はRails 5のアプリケーションで3つのアクティブレコードの配列をマージしようとしています。ホームページにジョブ、フォーラムスレッド、ブログを集めています。3つのアクティブなレコードの配列をマージする

I次のコードを持っている:

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ページに表示されたコレクションには表示されません。しかし、データベースからすべてのレコードを削除して新しいレコードを追加すると、コードはうまく動作し、予想通りの動作で正しい順序で投稿を表示します。

実稼働環境に既に存在するレコードをすべて削除することができないため、私はこのコードをライブヘロクにプッシュできません。ほとんどの場合、クリアする必要のあるキャッシュがあります。誰が何が起こっているのか分かっていますか?

答えて

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

など

+0

原則として良いです。私は 'Blog.order(created_at::desc).limit(6)'を提案します。そうでなければ、注文の前に限度が与えられ、最新のものは含まれません。 – SteveTurczyn

+0

これを行うと、3つの異なるコレクションがグループ化されます。だから、すべてのブログ記事はお互いに隣り合っていて、隣同士の仕事は...私はそれらをすべて一緒にして、ソートしてください。 – 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:あなたはいつもの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 :: Relationsのために。

config/initializers/extensions.rb

require 'array_extensions' 

問題3:クリーンコントローラを維持

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

lib/array_extensions.rb、その後は初期化と拡張を必要とします。

一般に、各コントローラアクションは1つのインスタンス変数のみを設定する必要があります。この場合は、ビューで@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:もし/そして、あなたのビュー内のロジックを最小化

の代わりにこの:

<% @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文を避けるためにコードをリファクタリングしました。私はあなたがアプリケーション/パーシャル/ホーム_#{item.class.name.underscore} "を実行できるかどうかも知りませんでした。"何か新しいことを教えてくれてありがとう – BillyBib

+0

うれしかったことがうれしいです! – Trip

関連する問題