💡
Ruby で Hash#merge の変わりに { **attributes } を利用する
例えば以下のようにキーワード引数のデフォルト値を指定するときに Hash#merge
を利用したい場合があります。
def user_create(**attributes)
# attributes を優先しつつ、active, country のデフォルト値を指定する
User.create({
active: true,
country: "日本"
}.merge(attributes))
end
# こっちはデフォルト値が利用される
user_create(name: "homu")
# こっちは指定した値を優先して利用される
user_create(name: "mami", country: "アメリカ")
こういうときに Hash の **
を利用すると #merge
を使わずにすっきり書けます。
def user_create(**attributes)
# **attributes すると {} の中に直接 **attributes の中身が展開される
User.create({
active: true,
country: "日本",
**attributes
})
end
JavaScript のスプレッド構文みたいな書き方ですね。
ただし、上記の場合は問題ないんですが attributes
が nil
の場合だと **
はうまく動かないので注意する必要があります。
# 何かしらの理由で attributes が nil になっている場合
attributes = nil
# **nil するとエラーになってしまう
# error: no implicit conversion of nil into Hash (TypeError)
{
active: true,
country: "日本",
**attributes
}
上記の挙動は以下のチケットによって将来的に改善されるかもしれません(既に matz の同意は得ており、あとはどう実装するのかだけ。
Discussion