2013-06-24 57 views
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可用。請注意,這不僅僅是我可以使用的方法助手,因爲有時它需要使用商店的貨幣(例如產品),有時還需要公司的貨幣(在CompanyUser,UserTransaction等情況下)。

理想情況下,我想要做的是:product.to_currency(product.price)或product.price.to_currency,它會通過檢查商店的貨幣來查找要使用的貨幣。

這個例子被簡化了,我也有一些其他的模型有一些需要轉換的數量,但所有的模型都可以連接到商店或公司。

+0

調用包括'::的ActionView在Helpers'全球範圍內是一個壞主意。你在全球範圍內混合這種行爲。 – d11wtq

+0

您是否考慮將此方法放入模塊並在需要的地方進行混合? – d11wtq

回答

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


到imple方法你需要猴子補丁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 
+0

太棒了!我想知道的一件事。有沒有辦法將@ client_order.to_currency(@ client_order.products_amount)) 重寫爲@client_order。to_currency(:products_amount))函數知道它應該查找該字段? – rept

+0

用public_send更新,send也可以 – house9

1

您可以使用through關聯通過相關遍歷來關聯記錄。和/或一些明確如下內容(但請注意每個對象遍歷將達到DB):

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