如何在模型中使用“number_to_currency”辅助方法而不是视图?

我想在我的模型中使用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'为#<Job:0x311eb00>

任何想法如何使其工作?

这是不可用的,因为它在模型中的使用(通常)违反MVC(它似乎在你的情况)。 你正在采集数据并操纵它进行演示。 按照定义,这属于视图而不是模型。

以下是一些解决scheme:

  • 使用演示者或视图模型对象在模型和视图之间进行调解。 这几乎肯定需要比其他解决scheme更多的初始工作,但几乎总是一个更好的devise。 在演示者/视图模型中使用助手不违反MVC,因为它们驻留在视图层中,取代了传统的自定义Rails助手和逻辑填充视图。

  • JobsHelper显式地include ActionView::Helpers::NumberHelper ,而不是依靠Rails来为你神奇地加载它。 这还不是很好,因为你不应该从模型中获得帮手。

  • 违反MVC和SRP 。 见fguillen的答案是如何做到这一点。 我不会在这里回应,因为我不同意。 但是,更为重要的是,我不同意用Sam的答案来污染你的模型。

如果你认为“但是我真的需要这个在我的模型中编写我的to_csvto_pdf方法!”,那么你的整个前提是错误的 – 毕竟,你没有to_html方法,是吗? 而你的对象经常被渲染成HTML。 考虑创build一个新的类来生成输出,而不是让你的数据模型知道什么是CSV( 因为它不应该 )。

至于在模型中使用助手的ActiveModelvalidation错误,那么,我很抱歉,但是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 

我同意你们所有人的看法,这可能会打破MVC模式,但是总有一些理由要打破模式,在我的情况下,我需要这些货币格式化方法 在模板filter中使用它们 (在我的情况下是Liquid )。

最后,我发现我可以使用这样的东西访问这些货币格式化方法

 ActionController::Base.helpers.number_to_currency 

我知道这个线程是非常古老的,但是有人可以在Rails 4中寻找这个问题的解决scheme。开发人员添加了ActiveSupport :: NumberHelper,可以使用它,而无需访问视图相关的模块/类使用:

 ActiveSupport::NumberHelper.number_to_currency(amount, precision: 0) 

你还需要包含ActionView :: Helpers :: NumberHelper

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

捎带@fguillen的回应,我想覆盖我的ApplicationHelper模块中的number_to_currency方法,以便如果值为0blank ,它会输出破折号。

这是我的代码,如果你们会发现这样的有用的东西:

 module ApplicationHelper def number_to_currency(value) if value == 0 or value.blank? raw "&ndash;" else ActionController::Base.helpers.number_to_currency(value) end end end 

@ fguillen的方式是好的,虽然这是一个稍微干净的方法,特别是考虑到这个问题有两个引用to_dollar 。 我将首先演示使用Ryan Bates的代码( http://railscasts.com/episodes/132-helpers-outside-views )。

 def description "This category has #{helpers.pluralize(products.count, 'product')}." end def helpers ActionController::Base.helpers end 

注意调用helpers.pluralize 。 这可能是由于方法定义( def helpers ),它只是返回ActionController::Base.helpers 。 因此helpers.pluralizeActionController::Base.helpers.pluralize 。 现在,您可以多次使用helpers.pluralize ,而不必重复长模块path。

所以我想这个问题的答案可能是:

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

您可以直接从您的控制器或模型使用view_context.number_to_currency

真的很惊讶没有一个人谈到使用装饰者。 他们的目的是为了解决你所面临的问题,以及更多。

https://github.com/drapergem/draper

编辑:看起来像接受的答案基本上build议做这样的事情。 但是,你想使用装饰器。 这里有一个很好的教程系列,可以帮助你更好地理解:

https://gorails.com/episodes/decorators-from-scratch?autoplay=1

PS – @ excid3我接受免费会员月LOL

这不是一个好的做法,但它适用于我!

在控制器中导入包括ActionView :: Helpers :: NumberHelper。 例如:

 class ProveedorController < ApplicationController include ActionView::Helpers::NumberHelper # layout 'example' # GET /proveedores/filtro # GET /proveedores/filtro.json def filtro @proveedores = Proveedor.all respond_to do |format| format.html # filtro.html.erb format.json { render json: @proveedores } end end def valuacion_cartera @total_valuacion = 0 facturas.each { |fac| @total_valuacion = @total_valuacion + fac.SumaDeImporte } @total = number_to_currency(@total_valuacion, :unit => "$ ") p '*'*80 p @total_valuacion end end 

希望它可以帮助你!

辅助方法通常用于查看文件。 在Model类中使用这些方法并不是一个好习惯。 但是如果你想使用,那么山姆的答案是好的。 或者我build议你可以编写自己的自定义方法。