LoginSignup
0
0

More than 1 year has passed since last update.

【Rails】異なるモデル同士の情報を紐づける必要性とその方法

Posted at

どうした?

ProgateのRailsレッスンにてSNSサイトを作成していくなかで、投稿に関するモデルとユーザーに関するモデルを紐づける方法を学びました。

本記事では

  • 異なるコントローラを紐づける必要性
  • コントローラ同士を紐づける方法

を初学者なりに整理したものです。

目標物の確認

今回作成したいページはこのような見た目です。
スライド1.JPG

準備したもの

今回の目標物を実現するために最低限必要なファイルは以下です。

モデル

Postモデル 投稿に関するモデル
idカラム: 投稿idとして使用。モデルに情報が入力されると自動生成される。
contentカラム: 投稿内容
user_idカラム: 投稿者のユーザーid。誰が投稿したか?を示す。

Userモデル ユーザーに関するモデル
idカラム: ユーザーidとして使用。モデルに情報が入力されると自動生成される。
nameカラム: ユーザー名
image_nameカラム: ユーザーが登録したユーザーに紐づく画像ファイル

コントローラ

postsコントローラ
showアクション: 投稿内容を表示する
showアクション内では、どのidの投稿かをparams[:id]で受け取り、そのidをもつ投稿情報(インスタンス形式)を@postに代入しています。

posts_controller.rb
# showアクション内で
@post = Post.find_by(id: params[:id])

params[:id]はurlから得られる値です。

(usersコントローラ)
もちろん存在はしますが、今回の機能実装に必要なアクションはありません。

ビューファイル

posts/show
目標物を表示するためのビューファイルです。

ルーティング

route.rb
get "posts/:id" => "posts/show"

url内の:idによってどの投稿を表示しているか?を示します。

異なるコントローラを紐づける必要性

今、投稿内容を表示するページを作るとします。

投稿内容の詳細を表示するshow.html.erb 内で、

  • 投稿内容
  • ユーザー名
  • ユーザー画像

を表示したいとき、
投稿内容 を表示するにはビューファイルで

show.html.erb
# 投稿内容
@post.content

で表します。
@postparams[:id]によって定義されているので、投稿内容はページがもつ情報だけで表示することができます。

では、ユーザー名やユーザー画像はどのように表示させれば良いでしょうか?
paramsハッシュにはユーザーに関する情報はありませんので、ページが持つ情報だけでユーザーを定義することができません。
ページがもつ情報からユーザーを割り出すとき、投稿とユーザーを紐づける必要性が発生します。
スライド2.JPG

コントローラ同士を紐づける方法

異なるコントローラを紐づける方法として、下記の3種類を紹介します。

  • アクション内で2重構造の定義をする
  • モデル内で定義したメソッドを変数に対して行う
  • has_one、has_manyとbelongs_to

これらについてまとめます。

アクション内で2重構造の定義をする

2重構造の定義(私が勝手に使っている言葉です)とは、params情報だけで完結する変数を定義し、その変数を用いて別の変数を定義する方法です。
showアクション内でユーザー情報を定義するには

posts_controller.rb
# showアクション内で
@post = Post.find_by(id: params[:id])
@user = User.find_by(id: @post.user_id)

と、@postuser_idカラム情報をユーザーidに代入することで@userを定義します。

これを用いると投稿詳細ページで

show.html.erb
# ユーザー名
@user.name

# ユーザー画像
@user.image_name

で表示することができます。
.name.image_nameはUserポストが持つカラムに対応する値を呼び出すメソッドです。
スライド3.JPG

モデル内で定義したメソッドを変数に対して行う

先ほど紹介した方法だと、すべてのアクションで@userとPostモデルを紐づける定義をする必要があります。
また、投稿一覧を表示するために@posts = Post.allに対してeach文を使うときに@userの定義が複雑になります。
@posts.eachで生成される変数postは、Postモデルに紐づいているため)

そこで、Postモデル内でユーザー情報と紐づけるメソッドを定義します。

post.rb
#クラス定義式内で
def user
  return User.find_by(id: self.user_id)
end

ここで、self.user_idはPostモデル自身が持つインスタンス変数(カラム)です。

これにより投稿詳細ページで

show.html.erb
# ユーザー名
@post.user.name

# ユーザー画像
@post.user.image_name

により、変数@postを使用してユーザー情報を出力できます。

解説
モデルファイル内で定義したuserメソッドを@postに対して行うと、その@postインスタンスが持つuser_idの値と一致するidを持つuserに関するインスタンスを検索することができます。
文章だとなんのこっちゃという感じなので、図解します。
スライド4.JPG

has_one、has_many、belongs_to

userとpostには主従関係があります。
userは複数のpostを持つことができるので、userが「主」、postが「従」の関係です。
「主」のモデルにはhas_oneもしくはhas_many
「従」のモデルにはbelongs_to
を設定することで、上で紹介したモデル内で定義したメソッドを変数に対して行うのと同じことができます。

user.rb
#userモデルファイル内で
has_many :post
post.rb
#postモデルファイル内で
belongs_to :user

を設定すると

# @postからユーザー名を出力
@post.user.name

# @userから投稿内容を全て出力
@user.post.each do |post|
  post.content
end
# ただし、@user = User.find(params[:id]) とする

が可能です。
これにより投稿詳細ページで

show.html.erb
# ユーザー名
@post.user.name

# ユーザー画像
@post.user.image_name

により、変数@postを使用してユーザー情報を出力できます。
ビューページのコード自体はモデル内で定義したメソッドを変数に対して行う方法と同じです。
スライド5.JPG

まとめ

本記事では

  • 異なるコントローラを紐づける必要性
  • コントローラ同士を紐づける方法

について記載しました。
コントローラ同士を紐づける方法として

  • アクション内で2重構造の定義をする
  • モデル内で定義したメソッドを変数に対して行う
  • has_one、has_manyとbelongs_to

を紹介しました。

Progateや書籍で勉強していると、「そもそもこの処理はなんで必要なんだっけ?」と思うことが多いです。
処理の必要性を意識して勉強していくとより身につくと感じました。

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