我有以下型号:
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)
如果我想显示公司用户的余额,我可以这样做:
company_user.company.currency.to_currency(company_user.balance)
如果我想显示我需要做的UserTransaction的价格:
user_transaction.company_user.company.currency.to_currency(user_transaction.amount)
这一切都有效。但我想知道是否存在我可以应用的设计模式,这将使所有连接对象中的to_currency可用。请注意,这不仅仅是我可以使用的方法助手,因为有时它需要使用商店的货币(例如使用产品),有时需要公司的货币(如果是CompanyUser,UserTransaction,......)。
理想情况下,我想这样做:product.to_currency(product.price)或product.price.to_currency,它会通过查看商店的货币来查找要使用的货币。
这个例子很简单,我还有其他一些模型需要转换,但所有这些都可以连接到商店或公司。
答案 0 :(得分: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
答案 1 :(得分: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