はじめに:privateなヘルパーメソッドを定義する?
Railsでは app/helpers
配下に自作のヘルパーモジュールを定義できます。
app/helpers/products_helper.rb
module ProductsHelper
def product_count
Product.count
end
end
ヘルパーメソッドの実装が複雑になってくるとメソッド分割したくなるかもしれません。
app/helpers/products_helper.rb
module ProductsHelper
# とても複雑なヘルパーメソッド
def build_complicated_value(product)
# ...
price = calc_complicated_price(product)
# ...
end
# 処理の一部を別メソッドに分割
def calc_complicated_price(product)
# ...
end
end
上のようなコードがあるとき、view(erb)から呼び出されるのは build_complicated_value
メソッドだけだったとします。
build_complicated_value(product) %>
calc_complicated_price
はviewから呼び出されないので、「このメソッドが使われるのはあくまでモジュールの中だけですよ」という意味で、このメソッドをprivateメソッドにしたくなるかもしれません。
app/helpers/products_helper.rb
module ProductsHelper
def build_complicated_value(product)
# ...
price = calc_complicated_price(product)
# ...
end
private
# このメソッドはprivateメソッド・・・?🤔
def calc_complicated_price(product)
# ...
end
end
しかし、残念ながら calc_complicated_price
はviewからの呼び出しを禁止することはできません。やろうと思えば普通にviewの中から呼び出せてしまいます。
calc_complicated_price(product) %>
なんで呼び出せちゃうの!?
これはProductsHelperがview(erb)にincludeされているためです。
viewとヘルパーモジュールの関係性を理解するための模擬的なサンプルコードを書くとすればこんな感じでしょうか。
# viewとヘルパーモジュールの関係性を理解するための模擬的なサンプルコード
class MyErbView
include ProductsHelper
def render_html
# ProductsHelperのpublicメソッドを呼び出す
build_complicated_value(product)
# ProductsHelperのprivateメソッドを呼び出す
calc_complicated_price(product)
end
end
Rubyのモジュールとinclude(ミックスイン)についてちゃんと理解している人であれば、上のコードを見て「ああ、そうか。そりゃ、publicもprivateも関係なく呼び出せちゃうよな」とわかるはずです。
結論:ヘルパーモジュールにprivateって書くな!
というわけで、ヘルパーモジュールにprivateキーワードを書くことは無意味です。
app/helpers/products_helper.rb
module ProductsHelper
def build_complicated_value(product)
# ...
price = calc_complicated_price(product)
# ...
end
# ❌ privateって書いても意味がない!!
private
def calc_complicated_price(product)
# ...
end
end
もしヘルパーモジュール内にprivate
があったら削除しちゃいましょう。
app/helpers/products_helper.rb
module ProductsHelper
def build_complicated_value(product)
# ...
price = calc_complicated_price(product)
# ...
end
- private
-
def calc_complicated_price(product)
# ...
end
end
viewから呼び出してほしくないヘルパーメソッドを定義するには?
「じゃあ、viewから呼び出してほしくないヘルパーメソッドを定義するにはどうしたらいいの?」と思うかもしれませんが、(僕が知る限り)Railsにはそのような機能は提供されていません。
もしやるなら、たとえば、アンダーバーをメソッド名の手前に付けて「違和感があるメソッド名」を演出する、とかでしょうか。
app/helpers/products_helper.rb
module ProductsHelper
def build_complicated_value(product)
# ...
price = _calc_complicated_price(product)
# ...
end
# アンダーバーを付けて呼び出しを躊躇しそうなメソッド名にする??
def _calc_complicated_price(product)
# ...
end
end
とはいえ、「アンダーバー付きのメソッドはprivateメソッドのつもりです!!」というオレオレルールを作っても、それはそれで混乱の元になりそうなのでイマイチですねえ。
僕個人の意見:ヘルパーはヘルパーらしく小粒なメソッドにすべし
僕個人の考えで言うと、ヘルパーメソッドは”ヘルパー”なんだから、なるべくあっさりした処理に抑えるべきだと思っています。
「メソッド分割したい」と思うぐらい長くて複雑なヘルパーメソッドは、「ヘルパーの範疇を超えているかも?」という黄色信号なので、専用のクラスに処理を切り出すなど、ヘルパーに頼らない解決策を模索した方がいいかもしれません。
publicでも別にええやん、と考えるのも一手
もう一つの考え方として、「viewから呼び出されないメソッドがpublicになっていても気にしない」というのもアリだと思います。
app/helpers/products_helper.rb
module ProductsHelper
def build_complicated_value(product)
# ...
price = calc_complicated_price(product)
# ...
end
# viewからは呼び出されないけど、別に気にしない!!
def calc_complicated_price(product)
# ...
end
end
そういうメソッドが大量にある場合は考え物ですが、ほどほどであれば、「まいっか」で済ませてもいいんじゃないでしょうか。
まとめ
というわけで、この記事ではRailsのヘルパーメソッドはprivateメソッドにできない、というかprivateメソッドにしても意味がない、という話を書いてみました。
今まで意識してこなかった人は手元のRailsプロジェクトのヘルパーモジュールにprivateキーワードが含まれていないか、以下のコマンドを使ってチェックしてみましょう!
git grep '^\s*private' -- app/helpers/
あわせて読みたい
ヘルパーメソッドを定義する際は名前の重複にも配慮しないといけません。
詳しくは以下の記事をご覧ください。
Views: 0