はじめに
プログラミング学習をする中で、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 }**
Railsのストロングパラメーターでよく見る。
使用例
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 メソッドは
クエリ条件を結合するためのメソッドです。
これは、データベースクエリに対して追加の条件を結合するために使用されます。例えば、where や joins の条件を組み合わせてクエリを生成するのに使います。
例えば、以下のように merge メソッドを使用してクエリ条件を結合できます。
# 最初のクエリ条件を定義
query1 = User.where(role: 'admin')
# さらに条件を追加する
query2 = query1.merge(User.where(status: 'active'))
この例では、query1 と query2 は異なるクエリ条件を持ちますが、merge メソッドを使用して query1 に query2 を結合することで、両方の条件を持つ新しいクエリを作成します。
ちなみに、公式ドキュメントにはこう書いてあります。(ざっくり翻訳)
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 メソッドがどのように使用されるかに注意が必要。
このようなメソッドが他にもあるので、手を動かす中で少しずつ慣れていきたいですね。
参考