DRYing Views в Rails (number_to_currency) - PullRequest
       30

DRYing Views в Rails (number_to_currency)

11 голосов
/ 09 сентября 2009

У меня есть код, похожий на:

number_to_currency(line_item.price, :unit => "£")

засоряет мои взгляды в разных моделях. Поскольку мое приложение работает только в фунтах стерлингов (£), я не должен перемещать это в каждую из моих моделей, чтобы line_item.price возвращала строку в том виде, в каком она должна быть (т.е. number_to_currency(line_item.price, :unit => "£") и line_item.price одинаковы. Я думаю, что для этого мне надо:

def price
 number_to_currency(self.price, :unit => "£")
end

но это не работает. Если price уже определено в модели, то Rails сообщает, что «слишком большой уровень стека», когда я изменяю def price на def amount, тогда он жалуется, что number_to_currency не определен?

Ответы [ 6 ]

41 голосов
/ 14 декабря 2010

Если вы хотите изменить настройки по умолчанию для всего вашего приложения, вы можете отредактировать config / locales / en.yml

Шахта выглядит так:

# Sample localization file for English. Add more files in this directory for other locales.
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
"en":
  number:
    currency:
        format:
            format: "%u%n"
            unit: "£"
            # These three are to override number.format and are optional
            separator: "."
            delimiter: ","
            precision: 2

Все, кроме устройства, является необязательным и будет иметь значение по умолчанию, но я вставил его, чтобы знать, какие значения я могу изменить. Вы также можете использовать знак £ вместо & pound;.

13 голосов
/ 09 сентября 2009

number_to_currency - помощник вида, поэтому он недоступен в моделях.

Вы можете сохранить некоторые нажатия клавиш, определив свой собственный помощник в application_helper.rb (чтобы он был доступен для всех представлений). Например,

def quid(price)
  number_to_currency(price, :unit => "£")
end

Тогда назовите это в представлениях:

quid(line_item.price)
6 голосов
/ 09 сентября 2009

Причина слишком большого уровня стека заключается в том, что когда вы говорите self.price в методе price, вы создаете бесконечный рекурсивный вызов метода цены, поскольку теперь вы переопределяете нормальный метод доступа. Чтобы избежать этого, вам нужно получить доступ к значению поля цены, используя хэш атрибутов. например что-то вроде:

def price
 number_to_currency(attributes['price'], :unit => "£")
end

за исключением того факта, что number_to_currency недоступен в коде модели по причине, описанной Ларри К.

2 голосов
/ 03 ноября 2009

Вот мой подход к этой проблеме ..

# /RAILS_ROOT/lib/app_name/currency_helper.rb
module AppName
  module CurrencyHelper    

    include ActionView::Helpers::NumberHelper

    def number_to_currency_with_pound(amount, options = {})
      options.reverse_merge!({ :unit => '£' })
      number_to_currency_without_pound(amount, options)
    end

    alias_method_chain :number_to_currency, :pound

  end
end

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

class Album < ActiveRecord::Base
  include AppName::CurrencyHelper

  def price
    currency_to_number(amount)
  end
end

затем, чтобы ваши представления обновлялись, включите модуль в один из помощников вашего приложения

module ApplicationHelper
   # change default currency formatting to pounds..
   include AppName::CurrencyHelper
end

Теперь везде, где вы используете число, чтобы поменять валюту, оно будет отформатировано с символом фунта, но у вас также есть вся гибкость оригинального метода rails, поэтому вы можете передавать опции, как вы делали раньше.

number_to_currency(amount, :unit => '$')

преобразует его обратно в символ доллара.

1 голос
/ 09 февраля 2011

По состоянию на рельсы 3

Как описывает Ларри К, но с этим редактированием:

def quid(price)
   number_to_currency(price, :unit => "&pound;")
 end
1 голос
/ 09 сентября 2009

Другой ответ, касающийся создания другого вспомогательного метода quid (цена) для упрощения повторения, вероятно, является лучшим подходом ... однако ... если вы действительно хотите получить доступ к помощникам вида в модели, вы можете сделать что-то вроде:

# /RAILS_ROOT/lib/your_namespace/helper.rb
#
# Need to access helpers in the model?
# YourNamespace::Helper.instance.helper_method_name
module YourNamespace
  class Helper
    include Singleton
    include ActionView::Helpers
  end
end

тогда вы сможете сделать это в классе модели:

def price
  helper = YourNamespace::Helper.instance
  helper.number_to_currency(read_attribute('price'), :unit => "£")
end
...