[mapメソッド]🍟追記: whereとの違い/joins
はじめに
最近mapメソッドを使ったので備忘録として記載して行きます。
mapメソッドとは?
mapメソッドを一言で表すと「各要素へ順に処理を実行してくれるメソッド」
配列の各要素に対してブロックを評価し、その結果を新しい配列として返す。。。。🙉ぁ?
イメージできないので今回やったことを具体例として記録しておきます。
前提
・今回のlike/indexページでは、そのユーザーがいいねした投稿(post)一覧を表示したい!
・アソシエーションは済
def index
@liked_posts = @user.likes.map(&:post)
end
このコードでは、@userが持つlikesという関連モデル(has_manyで関連付けられたモデル)からpostを取得。
mapメソッドは、配列やコレクションの各要素に対してブロックを実行し、その結果を新しい配列として返すことができる。つーまーりー🪿
その情報(今回ならpost情報)を配列にしてくれる。
その新しい配列は 今回は@liked_posts に格納される。
それをビューで使用して、特定の操作(例えば、投稿の画像を表示するなど)を行うことができる。🦆
なるほどーーーーーー!!!!!
補足
じゃあ逆にその投稿をいいねした人を出力したかったら
@liked_users = @post.likes.map(&:user)
でviewで
<%= @liked_users.each do |liked_user| %>
<%= @liked_users.name %>
<% end %>
とかで出力できるってわけね〜〜〜〜〜〜🌝
やっと理解できて嬉しい〜
7/23 追記
def show
@post = Post.find(params[:post_id])
@liked_users = @post.likes.map(&:user)
end
を下記に変更
def show
@post = Post.find(params[:post_id])
@liked_users = User.joins(:likes).where(likes: { post_id: @post.id })
end
def index
@user = User.find(params[:id])
@liked_posts = @user.likes.map(&:post)
end
を下記に変更
def index
@user = User.find(params[:id])
@liked_posts = Post.joins(:likes).where(likes: { user_id: @user.id })
end
where メソッド
[特徴]
・データベースに対してSQLクエリを実行し、その結果を返します。
(今回ならpostに紐付いたlikeテーブルに紐付いたuserテーブルのuser.idだけを持ってくる)
・非常に効率的で、大量のデータを扱う際には特に有用です。
mapメソッド
[特徴]
・@post オブジェクトをデータベースから取得。
・@post.likes で関連する Like オブジェクトをすべて取得し、メモリにロード。
・各 Like オブジェクトの user メソッドを呼び出して、それぞれのユーザーを取得
(今回ならpostに紐付いたlikeテーブル[オブジェクト]の情報、またlikeに紐付いたuserの情報を一回全部取得してメモリにロードしてそこから必要なuser_id持ってくる)
結論mapより効率がいいため変更🦉
[mapが有用なケース]
・mapは、コレクションの各要素に対してブロックを評価し、その結果を含む新しい配列を返します。例えば、特定の属性だけを抽出したい場合や、各要素に対して計算を行いたい場合に有用です。
・オブジェクトの特定の属性を配列として取得する場合
joins メソッド
[joinsの基本]
目的: 複数のテーブルを結合し、結合されたデータに基づいてクエリを実行するために使用します。
特に、関連するテーブルの情報を一緒に取得する際に便利。
Model.joins(:associationモデル[小文字])
# UserモデルがPostモデルに対して`has_many :posts`と関連付けられているとします。
# ユーザーとそのユーザーが投稿したすべてのポストを取得したい場合
# usersテーブルとpostsテーブルを結合し、特定の条件を満たすポストを取得
User.joins(:posts).where(posts: { title: 'Example' })
# users、posts、そしてcommentsテーブルを結合
User.joins(posts: :comments).where(comments: { approved: true })
# 条件を指定して結合
User.joins(:posts).where('posts.created_at > ?', 1.week.ago)
Discussion