Я хотел бы использовать метод 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
здесь не распознается:
undefined метод `number_to_currency 'для # < Job: 0x311eb00 >
Любые идеи, как заставить его работать?
Ответ 1
Его недоступно, потому что его использование в модели (как правило) нарушает MVC (и это похоже на ваш случай). Вы берете данные и манипулируете им для презентации. Это, по определению, принадлежит мнению, а не модели.
Вот несколько решений:
-
Используйте объект презентатора или объекта модели представления для посредничества между моделью и представлением. Это почти определенно требует большей начальной работы, чем другие решения, но почти всегда является лучшим дизайном. Использование помощников в презентационной /view -model не нарушает MVC, поскольку они находятся на уровне представления, заменяя традиционные пользовательские помощники Rails и заполненные логикой представления.
-
Явно include ActionView::Helpers::NumberHelper
в JobsHelper
вместо того, чтобы зависать от Rails, чтобы он волшебным образом загрузил его для вас. Это все еще не очень удобно, так как вы не должны обращаться к помощнику из модели.
-
Нарушить MVC и SRP. См. fguillens answer, как это сделать. Я не буду повторять это здесь, потому что я не согласен с этим. Тем не менее, не согласен ли я с загрязнением вашей модели с помощью методов представления, как в Ответ Sams.
Если вы думаете: "Но мне действительно нужно это, чтобы написать мои методы to_csv
и to_pdf
в моей модели!", тогда вся ваша предпосылка неверна. В конце концов, у вас нет метода to_html
, вы? И все же ваш объект очень часто отображается как HTML. Подумайте о создании нового класса для генерации вывода вместо того, чтобы ваша модель данных знала, что такое CSV (потому что он не должен).
Что касается использования помощников для ошибок проверки ActiveModel в модели, ну, извините, но ActiveModel/Rails прикололи нас всех туда, заставляя сообщения об ошибках реализовываться в слое данных, вместо того, чтобы возвращать семантическую идею ошибки для быть осознанным позже - вздох. Вы можете обойти это, но в основном это означает, что больше не использовать ActiveModel:: Errors. Ive сделал это, он работает хорошо.
В качестве альтернативы, это полезный способ включить помощников в презентационную/презентационную модель, не загрязняя ее набор методов (потому что возможность сделать, например, 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
Я согласен с вами в том, что это может сломать шаблон MVC, но всегда есть причины разбить шаблон, в моем случае мне нужны эти методы форматирования валют для использовать их в фильтре шаблона (Жидкость в моем случае).
В конце я узнал, что могу получить доступ к этим методам форматирования валют, используя такие вещи:
ActionController::Base.helpers.number_to_currency
Ответ 3
Я знаю, что эта ветка очень старая, но кто-то может найти решение этой проблемы в Rails 4+. Разработчики добавили ActiveSupport :: NumberHelper, который можно использовать без доступа к связанным с просмотром модулям/классам, используя:
ActiveSupport::NumberHelper.number_to_currency(amount, precision: 0)
Ответ 4
Вам также необходимо включить 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
Ответ 5
Отказываясь от ответа @fguillen
, я хотел переопределить метод number_to_currency
в моем модуле ApplicationHelper
, чтобы, если значение было 0
или blank
, вместо этого оно вывело бы тире.
Здесь мой код, если вы, ребята, найдете что-то вроде этого полезного:
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
Ответ 6
Вы можете использовать view_context.number_to_currency
непосредственно от вашего контроллера или модели.
Ответ 7
@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
Ответ 8
Это не очень хорошая практика, но она работает для меня!
для импорта включают 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
Надеюсь, это поможет вам!
Ответ 9
Действительно удивил, что никто не говорил об использовании Decorator. Их цель - решить проблему, с которой вы столкнулись, и многое другое.
https://github.com/drapergem/draper
EDIT: Похоже, что принятый ответ в основном предлагал сделать что-то подобное. Но да, вы хотите использовать декораторы. Вот отличный сериал, который поможет вам понять больше:
https://gorails.com/episodes/decorators-from-scratch?autoplay=1
P.S. - @excid3 Я принимаю бесплатные месяцы членства LOL
Ответ 10
Вы можете просто include ActiveSupport::NumberHelper
, если вам не нужны дополнительные функции, определенные ActionView
.
https://github.com/rails/rails/blob/44260581bec06e4ce05f3dd838c8b4736fc7eb1d/actionview/lib/action_view/helpers/number_helper.rb#L383
Ответ 11
Вспомогательные методы обычно используются для просмотра файлов.
Использовать эти методы в классе модели не рекомендуется.
Но если вы хотите использовать, то ответ Сэма в порядке.
ИЛИ Я предлагаю вам написать собственный собственный метод.