7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】複数モデルのインスタンスを一覧表示する

Last updated at Posted at 2020-10-09

実現させたいこと

YouTubeやFacebookのタイムラインのように、投稿と広告を作成降順に同じ画面に表示する機能が必要になった(通常なら広告は作成順の表示ではないかもしれないが、話を簡単にするために作成順で並べると仮定する)。

上記の状況に限らず、いくつかのモデルパターンを想定して、コントローラーでうまいこと取得し、ビューで並列して処理する方法を考える。

前提

バージョン

  • Ruby 2.6.3
  • Rails 5.2.3

ケース1

関連のないモデルを作成日順に並べる

# 投稿モデルと広告モデルはカラムが異なるとする

# 投稿モデル(Post)
  t.integer "user_id"
  t.string "content"
  t.string "image"
  t.datetime "created_at"
  t.datetime "updated_at"

# 広告モデル(Advertisement)
  t.integer "company_id"
  t.string "content"
  t.string "link_url"
  t.datetime "expired_date"
  t.datetime "created_at"
  t.datetime "updated_at"

実装方法

timeline_controller.rb
def index
  posts = Post.all
  ads = Advertisement.all

  # それぞれの複数インスタンスを1つの配列にする
  @instances = posts | ads
  # 作成降順(新しい順)に並び替え
  # 作成昇順の場合は、a.created_at <=> b.created_at }
  @instances.sort!{ |a, b| b.created_at <=> a.created_at }
end
index.html.erb
<% @instances.each do |instance| %>
  <% if instance.class == "Post" %>
    <%# Postの表示 %> 
    <%= instance.user_id %>
    <%= instance.content %>
    <%= instance.image %>
  <% else %>
    <%# Advertisementの表示 %> 
    <%= instance.company_id %>
    <%= instance.content %>
    <%= instance.link_url %>
  <% end %>
<% end %>

ケース2

関連のないモデルを異なるDate型カラムで日付順に並べる

# ケース1と同じ

# 投稿モデル(Post)
  t.integer "user_id"
  t.string "content"
  t.string "image"
  t.datetime "created_at"  <= これで並び替えたい
  t.datetime "updated_at"

# 広告モデル(Advertisement)
  t.integer "company_id"
  t.string "content"
  t.string "link_url"
  t.datetime "expired_date"  <= これで並び替えたい
  t.datetime "created_at"
  t.datetime "updated_at"

実装方法

timeline_controller.rb
def index
  posts = Post.all
  ads = Advertisement.all

  @instances = posts | ads
  # 投稿モデルの場合はcreated_atを、広告モデルの場合はexpired_dateで判定する
  @instances.sort! do |a, b|
    a_created_at = a.class == "Post" ? a.created_at : a.expired_date
    b_created_at = b.class == "Post" ? b.created_at : b.expired_date
    b_created_at <=> a_created_at
  end

ケース3

子がある場合は子の最新の作成日、ない場合は親の作成日を見て並べる

# トークルームモデル(TalkRoom)
  t.string "name"
  t.datetime "created_at"
  t.datetime "updated_at"

# 投稿モデル(Post)
  t.integer "talk_room_id"
  t.string "content"
  t.string "image"
  t.datetime "created_at"
  t.datetime "updated_at"

実装方法

timeline_controller.rb
def index
  @instances = TalkRoom.includes(:posts)
                       .order("posts.created_at DESC")
                       .to_a
  # 子モデルが存在するかを判定し、ある場合は最新の子モデルのcreated_at、ない場合は親のcreated_atで判定する
  @instances.sort! do |a, b|
    a_created_at = a.posts.present? ? a.posts.first.created_at : a.created_at
    b_created_at = b.posts.present? ? b.posts.first.created_at : b.created_at
    b_created_at <=> a_created_at
  end
end
7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?