Rails で content_tag メソッドの代わりに tag メソッドに使うように促す cop を次の RuboCop Rails 2.6.0 で導入する予定です。
以下、bad ケースと good ケースをサンプルから抜粋します。
# bad content_tag(:p, 'Hello world!') content_tag(:br) # good tag.p('Hello world!') tag.br
2020年5月14日追記
第一引数に変数をとるケースについては、public_send
を使うくらいなら content_tag
を使う方が良さそうです。
呼ばれてないけど、public_sendとか見苦しすぎるので、「content_tag の第一引数が変数の場合は無視する」じゃないすかね。
— Akira Matsuda (@a_matsuda) 2020年5月14日
現状、tagメソッドにcontent_tagメソッドの第二引数と同じ値を渡す方法が無い(blockでも渡せない)以上、日記に書かれている以外の解決方法は無さそうな印象でした。
— y-yagi (@y_yagi) 2020年5月14日
ただ、私もpublic_sendを使うなら、content_tagのままの方が良いのでは、という印象です。
以下は元記事として残していますが、これらの方法はとらない方が良いです。
PR の説明にあるように content_tag
はレガシーな API ということで、デフォルトで有効で良いと思っているものの、現状だと第一引数に変数をとる以下のケースに問題があります。
オートコレクトでコードが壊れることを防ぐため、以下の PR を問題解決のため開いていますが public_send
を使っているのが気にかかっている点です。
Case 1: NoMethodError
を防ぐ
元コード:
content_tag(name, 'foo', class: 'bar')
現状の auto-correct:
tag(name, 'foo', class: 'bar') #=> NoMethodError (undefined method `each_pair' for "foo":String)
今後:
tag.public_send(name, 'foo', class: 'bar')
Case 2: symbolize_keys
を使って ArgumentError
を防ぐ
元コード:
content_tag(name, 'foo', {'class' => 'bar'})
現状の auto-correct:
tag.public_send(name, 'foo', {'class' => 'bar'}) #=> `ArgumentError (wrong number of arguments (given 3, expected 1..2))`
今後:
symbolize_keys
を使って ArgumentError
を防ぐハックをしている。
引き渡されたハッシュのキーがすべてシンボルかどうか静的解析で検知がつらいための苦肉の策。
既存アプリケーションが壊れるのを防ぐためとはいえ、この解決はつらい。
tag.public_send(name, 'foo', {'class' => 'bar'}.symbolize_keys)
Case 3: ArgumentError
を防ぐため三項演算子を使っている
元コード:
content_tag(name, 'foo', options)
現状の auto-correct:
options = nil tag.public_send(name, 'foo', options) #=> `ArgumentError (wrong number of arguments (given 3, expected 1..2))`
options
が nil のときに ArgumentError
です。
今後:
tag.public_send(name, 'foo', options ? options.symbolize_keys : {})
なかなか厳しいものがあるので、content_tag
の第一引数が変数の場合は無視するという対応も考えられるものの、もっと良い tag
への変換があれば教えてもらえると嬉しいです (知らないだけでもっと良い tag
メソッドへの置換方法がある?) 。