Ruby-on-rails 如何在模型而不是视图中使用“number_to_currency”辅助方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5176718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use the "number_to_currency" helper method in the model rather than view?
提问by Misha Moroshko
I would like to use to_dollarmethod in my model like this:
我想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
Unfortunately, the number_to_currencymethod is not recognized here:
不幸的是,number_to_currency这里不承认该方法:
undefined method `number_to_currency' for #<Job:0x311eb00>
#<Job:0x311eb00> 的未定义方法 `number_to_currency'
Any ideas how to make it work?
任何想法如何使它工作?
回答by fguillen
I agree with all of you that this could be breaking the MVC pattern but there is always reasons to break a pattern, in my case I needed these currency formatter methodsto use them in a template filter(Liquidin my case).
我与大家同意,这可能是打破了MVC模式,但总是有原因打破格局,在我的情况,我需要这些货币格式化方法,以在模板过滤器中使用它们(液体在我的情况)。
At the end I found out I could access to these currency formatter methodsusing things like this:
最后我发现我可以使用这样的东西访问这些货币格式化程序方法:
ActionController::Base.helpers.number_to_currency
回答by Andrew Marshall
It's not available because its use in a model (typically) violates MVC (and it does seem to in your case). You're taking data and manipulating it for presentation. This, by definition, belongs in the view, not the model.
它不可用,因为它在模型中的使用(通常)违反了 MVC(在您的情况下似乎确实如此)。您正在获取数据并对其进行操作以进行演示。根据定义,这属于视图,而不属于模型。
Here are some solutions:
以下是一些解决方案:
Use a presenter or view model object to mediate between the model and view. This almost definitely requires more initial work than other solutions, but is almost always a better design. Using helpers in a presenter/view-model doesn't violate MVC, as they reside in the view layer, replacing traditional custom Rails helpers and logic-filled views.
Explicitly
include ActionView::Helpers::NumberHelperinJobsHelperinstead of depending on Rails to have magically loaded it for you. This is still not great, as you shouldn't access a helper from a model.Violate MVC & SRP. See fguillen's answerfor how to do this. I won't echo it here because I don't agree with it. Even more so, though, do I disagree with polluting your model with presentation methods as in Sam's answer.
使用演示者或视图模型对象在模型和视图之间进行调解。这几乎肯定比其他解决方案需要更多的初始工作,但几乎总是更好的设计。在演示者/视图模型中使用助手不会违反 MVC,因为它们驻留在视图层中,取代了传统的自定义 Rails 助手和逻辑填充视图。
明确地
include ActionView::Helpers::NumberHelper,JobsHelper而不是依赖于 Rails 为你神奇地加载它。这仍然不是很好,因为您不应该从模型访问帮助程序。违反 MVC & SRP。有关如何执行此操作,请参阅fguillen 的回答。我不会在这里附和,因为我不同意。但是,更重要的是,我是否不同意使用Sam 的回答中的表示方法污染您的模型。
If you think “but I really need this to write my to_csv& to_pdfmethods in my model!”, then your entire premise is wrong—after all, you don't have a to_htmlmethod, do you? And yet your object is very often rendered as HTML. Consider creating a new class for generating your output instead of making your data model know what a CSV is (because it shouldn't).
如果你认为“但我真的需要这个来在我的模型中编写我的to_csv&to_pdf方法!”,那么你的整个前提是错误的——毕竟,你没有to_html方法,是吗?然而你的对象经常被呈现为 HTML。考虑创建一个新类来生成您的输出,而不是让您的数据模型知道 CSV 是什么(因为它不应该)。
As for using helpers for ActiveModel validation errors in the model, well, I'm sorry but ActiveModel/Rails has screwed us all there by forcing error messages to be realized in the data layer, rather than returning the semantic ideaof an error to be realized later—sigh. You can get around this, but it basically means not using ActiveModel::Errors anymore. I've done it, it works well.
至于在模型中对 ActiveModel 验证错误使用帮助程序,我很抱歉,但 ActiveModel/Rails 通过强制在数据层中实现错误消息来把我们搞砸了,而不是返回错误的语义思想后来才明白——叹息。你可以解决这个问题,但这基本上意味着不再使用 ActiveModel::Errors。我已经做到了,效果很好。
As an aside, here's a useful way to include helpers in a presenter/view-model without polluting its set of methods (because being able to do e.g. MyPresenterOrViewModel.new.link_to(...)makes no sense):
顺便说一句,这是一种在演示者/视图模型中包含助手而不污染其方法集的有用方法(因为能够执行例如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
回答by Micha? Zalewski
I know this thread is very old, but someone can look for solution for this problem in Rails 4+. Developers added ActiveSupport::NumberHelper, which can be used without accessing view related modules/classes using:
我知道这个线程很老了,但是有人可以在 Rails 4+ 中寻找这个问题的解决方案。开发人员添加了 ActiveSupport::NumberHelper,它可以在不访问视图相关模块/类的情况下使用:
ActiveSupport::NumberHelper.number_to_currency(amount, precision: 0)
回答by Sam
You need to also include the ActionView::Helpers::NumberHelper
您还需要包括 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
回答by aarona
Piggybacking off of @fguillen's response, I wanted to override the number_to_currencymethod in my ApplicationHelpermodule so that if the value was 0or blankthat it would output a dash instead.
捎带@fguillen的响应,我想覆盖number_to_currency我的ApplicationHelper模块中的方法,以便如果该值是0或blank它会输出一个破折号。
Here's my code in case you guys would find something like this useful:
这是我的代码,以防你们发现这样有用的东西:
module ApplicationHelper
def number_to_currency(value)
if value == 0 or value.blank?
raw "–"
else
ActionController::Base.helpers.number_to_currency(value)
end
end
end
回答by Felipe M Andrada
You can use view_context.number_to_currencydirectly from you controller or model.
您可以view_context.number_to_currency直接从控制器或模型中使用。
回答by user664833
@fguillen's way is good, though here's a slightly cleaner approach, particular given that the question makes two references to to_dollar. I'll first demonstrate using Ryan Bates' code (http://railscasts.com/episodes/132-helpers-outside-views).
@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
Notice the call helpers.pluralize. This is possible due to the method definition (def helpers), which simply returns ActionController::Base.helpers. Therefore helpers.pluralizeis short for ActionController::Base.helpers.pluralize. Now you can use helpers.pluralizemultiple times, without repeating the long module paths.
注意调用helpers.pluralize。这是可能的,因为方法定义 ( def helpers) 只返回ActionController::Base.helpers。因此helpers.pluralize是 的缩写ActionController::Base.helpers.pluralize。现在您可以helpers.pluralize多次使用,而无需重复冗长的模块路径。
So I suppose the answer to this particular question could be:
所以我想这个特定问题的答案可能是:
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
回答by alexventuraio
It is not a good practice but it works for me!
这不是一个好习惯,但它对我有用!
to import include ActionView::Helpers::NumberHelper in the controller. For example:
导入在控制器中包含 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
Hope it helps you!
希望对你有帮助!
回答by Greg Blass
Really surprised not one person has talked about using a Decorator. Their purpose is to solve the issue you are facing, and more.
真的很惊讶没有人谈论过使用装饰器。他们的目的是解决您面临的问题,等等。
https://github.com/drapergem/draper
https://github.com/drapergem/draper
EDIT: Looks like the accepted answer basically did suggest doing something like this. But yeah, you want to use decorators. Here's a great tutorial series to help you understand more:
编辑:看起来接受的答案基本上确实建议做这样的事情。但是,是的,您想使用装饰器。这是一个很棒的教程系列,可帮助您了解更多信息:
https://gorails.com/episodes/decorators-from-scratch?autoplay=1
https://gorails.com/episodes/decorators-from-scratch?autoplay=1
P.S. - @excid3 I accept free membership months LOL
PS - @excid3 我接受免费会员月 LOL
回答by Artur Beljajev
You can just include ActiveSupport::NumberHelpermodule, if you don't need additional features defined by ActionView.
你可以只include ActiveSupport::NumberHelper模块,如果你不需要通过定义的附加功能ActionView。

