0

我有以下型号:

Shop, :belongs_to => Currency
Product, :belongs_to => Shop
Company, :belongs_to => Currency
CompanyUser, :belongs_to => Company
UserTransaction, :belongs_to => CompanyUser

所以一家商店和一家公司都使用某种货币。这是货币的模型

include ActionView::Helpers

class Currency < ActiveRecord::Base
  attr_accessible :description, :iso_code, :number_of_decimals, :symbol

  def to_currency(number)
    number_to_currency(number, :precision => self.number_of_decimals, :unit => self.symbol)
  end    
end

好的,现在当我想显示产品价格时,我可以这样做:

product.shop.currency.to_currency(product.price)

如果我想显示 CompanyUser 的余额,我可以这样做:

company_user.company.currency.to_currency(company_user.balance)

如果我想显示 UserTransaction 的价格,我需要这样做:

user_transaction.company_user.company.currency.to_currency(user_transaction.amount)

这一切都有效。但我想知道是否存在一种我可以应用的设计模式,它可以使 to_currency 在所有连接的对象中可用。请注意,它不仅仅是我可以使用的方法助手,因为有时它需要使用 Shop 的货币(例如使用 Product),有时还需要使用 Company 的货币(在 CompanyUser、UserTransaction 的情况下......)。

理想情况下,我想做:product.to_currency(product.price) 或 product.price.to_currency,它会通过检查商店的货币来查找要使用的货币。

此示例已简化,我还有几个其他模型需要转换的金额,但所有这些都可以连接到 Shop 或 Company。

4

2 回答 2

1

您可以使用through关联通过相关遍历来关联记录。和/或类似以下的明确内容(但要注意每个对象遍历都会命中数据库):

class CompanyUser
  def currency
    company.currency
  end
end

class UserTransaction
  def currency
    company_user.currency
  end

  def to_currency
    currency.to_currency(amount)
  end
end

# ...
puts UserTransaction.find(5).to_currency
于 2013-06-24T23:11:12.720 回答
1

product.to_currency(product.price)上班,你可以做这样的事情

# common module that can be used with any object that has a currency method or attribute
module HasCurrency
  def to_currency(value)
    if respond_to?(:currency)
      currency.to_currency(value)
    else
      raise "#{class} does not have a currency"
    end
  end
end


class Product
  # mix in the module, but...
  include HasCurrency

  belongs_to :shop
  # ... product has no currency method, delegate it to the associated shop
  delegate :currency, to: :shop

  # delegate is the same as
  def currency
    shop.currency
  end
end

上面的注释对您UserTransaction来说效果不佳,请参阅 z5h 答案,您需要包装关联并公开的方法currency


要实现product.price.to_currency,您需要对 BigDecimal 进行猴子补丁(如果这是价格类型),它会有点棘手;相反,使用简单的包装方法可能会更好?

不可重复使用,但明确且易于理解

class Product
  belongs_to :shop

  def formatted_price
    shop.currency.to_currency(price)
  end
end

从符号调用方法

def to_currency(method_name)
  self.public_send(method_name) if self.respond_to?(method_name)
end
于 2013-06-24T23:35:58.917 回答