8
7

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 1 year has passed since last update.

【Ruby・Rails】mergeメソッドの2つの働き

Last updated at Posted at 2023-10-04

はじめに

プログラミング学習をする中で、mergeメソッドの挙動の違いに遭遇したのでまとめてみました。

先に結論

Rubyにおける場合と、RailsのActiveRecordにおける場合でmergeメソッドの処理が変わる。

どのレシーバーに対して使っているかがポイント

Rubyのハッシュの merge メソッド

2つのハッシュを結合して新しいハッシュを作成します。
このメソッドは、ハッシュのキーと値を結合し、重複するキーがある場合は後からマージされたハッシュの値が優先されます。
以下は、merge メソッドを使用して2つのハッシュを結合する例です。

hash1 = { a: 1, b: 2 }
hash2 = { b: 3, c: 4 }
merged_hash = hash1.merge(hash2)

puts merged_hash 
=> **{ a: 1, b: 3, c: 4 }**

Ruby リファレンスマニュアルの説明はこちら

Railsのストロングパラメーターでよく見る。

使用例

controllers.rb
private
  def user_order_params
    params.require(:user_order).permit(:postal_code, :prefecture_id).merge(user_id: current_user.id, item_id: params[:item_id])
  end

item_id: params[:item_id]で値を入れることができるのは、ルーティングをネストし、URLにitem_idを含めているため。ストロングパラメーターはprivateメソッド以下に記述する。

requireの引数は、モデル名。
permitの引数は、DBのカラム名。

ターミナルで確認できるパラメーター

 "user_order"=>{"hoge"=>"", "postal_code"=>"", "prefecture_id"=>"1"}, "commit"=>"購入", "controller"=>"orders", "action"=>"create", "item_id"=>"7"}

mergeメソッドを使う場面

 form_withでユーザーが記入した内容はハッシュの中に、キーと一緒に入っているが、ユーザーが記入しない内容も保存したい時。
例えば、ユーザーのidやその商品のidについては、ユーザーが直接入力することはないが、パラメーターに含めて、DBの保存したい。そのような時に、mergeメソッドを使って、パラメーターに含めたいキーと値を記述する。
上記の例では、user_idをcrrent_user.idから、item_idをURLに含めたparamsから取ってきて、パラメーターに含めている。

RailsのActiveRecordにおける merge メソッドは

クエリ条件を結合するためのメソッドです。
これは、データベースクエリに対して追加の条件を結合するために使用されます。例えば、wherejoins の条件を組み合わせてクエリを生成するのに使います。

例えば、以下のように merge メソッドを使用してクエリ条件を結合できます。

# 最初のクエリ条件を定義
query1 = User.where(role: 'admin')

# さらに条件を追加する
query2 = query1.merge(User.where(status: 'active'))

この例では、query1query2 は異なるクエリ条件を持ちますが、merge メソッドを使用して query1query2 を結合することで、両方の条件を持つ新しいクエリを作成します。

ちなみに、公式ドキュメントにはこう書いてあります。(ざっくり翻訳)

Railsのmergeメソッドは、ActiveRecord::Relation同士を結合するためのもの。
これを使うと、あるクエリの結果に対して別のクエリの条件を追加することができる。

例えば、Post.where(published: true).joins(:comments).merge(Comment.where(spam: false))というコードは、「公開済みの投稿」+「スパムでないコメントがついているもの」を取得するためのクエリとなる。

また、Post.where(published: true).merge(-> { joins(:comments) })という書き方でも同じクエリを発行できる。
ここでの-> { joins(:comments) }はProcという特殊なオブジェクトで、この中に書かれたコードがmergeメソッドによって評価される。

このように、mergeメソッドを使えば、複数のクエリの条件を一箇所で管理することができる。
結果としてコードがシンプルになり、繰り返しを避けることもできる

公式ドキュメントはこちら

まとめ

2つの merge メソッドは、異なるレシーバー(コンテキスト)で異なる動作をするメソッド。
それぞれのレシーバー(コンテキスト)で merge メソッドがどのように使用されるかに注意が必要。

このようなメソッドが他にもあるので、手を動かす中で少しずつ慣れていきたいですね。

参考

8
7
2

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?