Как использовать вспомогательный метод "number_to_currency" в модели, а не в представлении? - PullRequest
87 голосов
/ 03 марта 2011

Я хотел бы использовать метод 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 'для #

Есть идеи, как заставить это работать?

Ответы [ 11 ]

173 голосов
/ 03 мая 2011

Я согласен со всеми вами, что это может нарушить шаблон MVC, но всегда есть причины нарушать шаблон, в моем случае мне понадобились эти методы форматирования валюты до , использующие их в шаблон фильтра ( жидкость в моем случае).

В конце я узнал, что могу получить доступ к этим методам форматирования валюты , используя такие вещи:

ActionController::Base.helpers.number_to_currency
94 голосов
/ 03 марта 2011

Он недоступен, потому что его использование в модели (как правило) нарушает MVC (и, похоже, в вашем случае).Вы берете данные и манипулируете ими для представления.Это, по определению, относится к представлению, а не к модели.

Вот некоторые решения:

  • Используйте объект презентатора или представления модели для посредничества между моделью иПосмотреть.Это почти наверняка требует больше начальной работы, чем другие решения, но почти всегда лучший дизайн.Использование помощников в презентере / модели представления не нарушает MVC, поскольку они находятся в слое представления, заменяя традиционные пользовательские помощники Rails и логические представления.

  • Явно include ActionView::Helpers::NumberHelperв JobsHelper вместо того, чтобы полагаться на то, что 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
61 голосов
/ 13 сентября 2015

Я знаю, что эта ветка очень старая, но кто-то может найти решение этой проблемы в Rails 4+. Разработчики добавили ActiveSupport :: NumberHelper, который можно использовать без доступа к модулям / классам, связанным с представлением, используя:

ActiveSupport::NumberHelper.number_to_currency(amount, precision: 0)
25 голосов
/ 03 марта 2011

Необходимо также включить 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
6 голосов
/ 24 октября 2013

Взаимодействуя с ответом @fguillen, я хотел переопределить метод number_to_currency в моем модуле ApplicationHelper, чтобы при значении 0 или blank вместо него выводилась бы тире.

Вот мой код на случай, если вы, ребята, найдете что-то подобное:

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
4 голосов
/ 18 мая 2015

Вы можете использовать view_context.number_to_currency непосредственно с вашего контроллера или модели.

3 голосов
/ 04 апреля 2012
Путь

@ fguillen хорош, хотя здесь немного более чистый подход, особенно учитывая, что в этом вопросе есть две ссылки на to_dollar. Сначала я продемонстрирую, используя код Райана Бейтса (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
2 голосов
/ 13 июля 2017

Действительно удивлен, что ни один человек не говорил об использовании Decorator. Их цель - решить проблему, с которой вы столкнулись, и многое другое.

https://github.com/drapergem/draper

РЕДАКТИРОВАТЬ: Похоже, принятый ответ в основном предлагал сделать что-то вроде этого. Но да, вы хотите использовать декораторы. Вот отличная серия учебников, которые помогут вам понять больше:

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

P.S. - @ excid3 Я принимаю бесплатные месяцы членства LOL

2 голосов
/ 22 ноября 2014

Это не очень хорошая практика, но она работает для меня!

для импорта включите 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

Надеюсь, это поможет вам!

0 голосов
/ 05 июня 2019

Вы можете просто include ActiveSupport::NumberHelper модуль, если вам не нужны дополнительные функции, определенные ActionView.

https://github.com/rails/rails/blob/44260581bec06e4ce05f3dd838c8b4736fc7eb1d/actionview/lib/action_view/helpers/number_helper.rb#L383

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...