1. ホーム
  2. ruby-on-rails

[解決済み] number_to_currency "ヘルパーメソッドをビューではなく、モデルで使用するには?

2023-01-03 13:37:27

質問

私は to_dollar メソッドを使いたいと思います。

module JobsHelper      
  def to_dollar(amount)
    if amount < 0
      number_to_currency(amount.abs, :precision => 0, :format => "-%u%n")
    else
      number_to_currency(amount, :precision => 0)
    end
  end      
end

class Job < ActiveRecord::Base
  include JobsHelper
  def details
    return "Only " + to_dollar(part_amount_received) + 
           " out of " + to_dollar(price) + " received."
  end
end

残念ながら number_to_currency メソッドはここでは認識されません。

未定義のメソッド `number_to_currency' for #<Job:0x311eb00>

どうすれば動くようになるのか、何かアイデアはありますか?

どのように解決するのですか?

モデルでの使用は(一般的に)MVCに違反するため、使用できません(あなたのケースではそのように見えます)。あなたはデータを取得し、プレゼンテーションのためにそれを操作しています。これは、定義上、モデルではなくビューに属します。

ここにいくつかの解決策があります。

  • モデルとビューの間を仲介するために、プレゼンターまたはビューモデルオブジェクトを使用します。これは他の解決策よりも間違いなく多くの初期作業を必要としますが、ほとんどの場合、より良い設計です。ヘルパーをプレゼンター/ビューモデルで使用しても、ビュー層に存在するためMVCには違反せず、従来のカスタムRailsヘルパーやロジック満載のビューに取って代わります。

  • 明示的に include ActionView::Helpers::NumberHelperJobsHelper を、Railsが魔法のように読み込んでくれることに依存するのではなく、の中に入れてください。モデルからヘルパーにアクセスすることはできないので、これはまだ素晴らしいことではありません。

  • MVC &に違反する。 SRP . 参照 fguillenの回答 をご覧ください。私はそれに同意しないので、ここで反響を呼ぶことはしません。それ以上に、以下のようなプレゼンテーション手法でモデルを汚染することに同意できません。 サムの答え .

もしあなたが、「でも、自分の文章を書くのにどうしてもこれが必要なんだ。 to_csv & を使用します。 to_pdf メソッドを持っていないのですから、その前提条件がすべて間違っています。 to_html メソッドはありませんよね?結局のところ、メソッドを持っていないのです。それなのに、あなたのオブジェクトは非常に頻繁にHTMLとしてレンダリングされます。データモデルにCSVが何であるかを認識させる代わりに、出力を生成するための新しいクラスを作成することを検討してください ( を使うべきではありませんから ).

ActiveModel の検証エラーのヘルパーをモデルで使うことについては、残念ですが ActiveModel/Rails はエラーメッセージをデータレイヤーで実現させることで、セマンティックな アイデア を返すのではなく、エラーメッセージをデータレイヤーで実現するよう強制しています。 ため息 . これを回避することは可能ですが、基本的には ActiveModel::Errors を使用しないことを意味します。私はそれをやりました、それはうまくいきます。

余談ですが、メソッドのセットを汚染することなく、ヘルパーをプレゼンター/ビューモデルに含めるための便利な方法があります (なぜなら、例えば MyPresenterOrViewModel.new.link_to(...) ができることは意味をなさないからです)。

class MyPresenterOrViewModel
  def some_field
    helper.number_to_currency(amount, :precision => 0)
  end

  private

  def helper
    @helper ||= Class.new do
      include ActionView::Helpers::NumberHelper
    end.new
  end
end