我想在我的模型中使用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
方法:
#&lt; Job:0x311eb00&gt;
的未定义方法`number_to_currency'
任何想法如何使其发挥作用?
答案 0 :(得分:171)
我同意你们所有人的意见,这可能会打破MVC模式,但总有理由打破模式,在我的情况下,我需要这些货币格式化方法来使用它们模板过滤器(在我的情况下, Liquid )。
最后我发现我可以使用以下内容访问这些货币格式化程序方法:
ActionController::Base.helpers.number_to_currency
答案 1 :(得分:92)
它不可用,因为它在模型中的使用(通常)违反了MVC(在你的情况下似乎确实如此)。您正在处理数据并对其进行操作以进行演示。根据定义,这属于视图,而不属于模型。
以下是一些解决方案:
使用演示者或视图模型对象在模型和视图之间进行调解。这几乎肯定需要比其他解决方案更多的初始工作,但几乎总是更好的设计。在演示者/视图模型中使用助手不会违反MVC,因为它们驻留在视图层中,取代了传统的自定义Rails助手和逻辑填充的视图。
在include ActionView::Helpers::NumberHelper
中明确JobsHelper
而非依赖Rails为您神奇地加载它。这仍然不是很好,因为你不应该从模型中访问帮助器。
违反MVC&amp; SRP。有关如何执行此操作,请参阅fguillen’s answer。我不会在此回应,因为我不同意。但更重要的是,我不同意使用Sam’s answer中的演示方法污染模型。
如果您认为“但我真的需要这样写to_csv
&amp;我的模型中的to_pdf
方法!“,那么你的整个前提是错误的 - 毕竟,你没有to_html
方法,对吗?然而,您的对象通常呈现为HTML。考虑创建一个用于生成输出的新类,而不是让您的数据模型知道CSV是什么(because it shouldn’t)。
至于在模型中使用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
答案 2 :(得分:57)
我知道这个帖子已经很老了,但有人可以在Rails 4+中寻找解决这个问题的方法。开发人员添加了ActiveSupport :: NumberHelper,可以在不使用以下方式访问与视图相关的模块/类的情况下使用:
ActiveSupport::NumberHelper.number_to_currency(amount, precision: 0)
答案 3 :(得分:25)
您还需要包含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
答案 4 :(得分:6)
抄袭@fguillen
的回复,我想覆盖number_to_currency
模块中的ApplicationHelper
方法,以便价值为0
或{{1}时它会输出一个破折号。
这是我的代码,以防你们发现这样的东西很有用:
blank
答案 5 :(得分:4)
您可以直接从控制器或型号使用view_context.number_to_currency
。
答案 6 :(得分:3)
@ 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.pluralize
是ActionController::Base.helpers.pluralize
的缩写。现在,您可以多次使用helpers.pluralize
,而无需重复长模块路径。
所以我想这个问题的答案可能是:
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
答案 7 :(得分:2)
这不是一个好习惯,但对我有用!
导入包括控制器中的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
希望它可以帮到你!
答案 8 :(得分:2)
真的很惊讶没有人谈过使用装饰器。他们的目的是解决您面临的问题,以及更多。
https://github.com/drapergem/draper
编辑:看起来接受的答案基本上建议做这样的事情。但是,你想要使用装饰器。这是一个很棒的教程系列,可以帮助您了解更多信息:
https://gorails.com/episodes/decorators-from-scratch?autoplay=1
P.S。 - @ excid3我接受免费会员月LOL
答案 9 :(得分:0)
如果您不需要include ActiveSupport::NumberHelper
定义的其他功能,则可以仅使用ActionView
模块。
答案 10 :(得分:-4)
Helper方法通常用于View文件。 在Model类中使用这些方法不是一个好习惯。 但是如果你想使用那么Sam的回答是可以的。 或者我建议您可以编写自己的自定义方法。