2013-11-01 55 views
0

我有兩個型號Rails中after_create回調的優雅替代方案?

class Contract < ActiveRecord::Base 
    has_many :transactions 
end 

class Transaction < ActiveRecord::Base 
    belongs_to :contract 
    after_create :mark_contract_as_live 
    def mark_contract_as_live 
    k = self.contract 
    if !k.is_live 
     k.update_attributes(:is_live => true) 
    end 
    end 
end 

is_live是在合同模型中的布爾字段。默認情況下,合同默認爲不生存(is_live => false)。當記錄第一筆交易時,它被標記爲活(is_live => true)。通過上面的解決方案,這意味着每次創建事務都需要調用數據庫來檢查合同是否有效。有沒有其他的選擇?

如果合同有成千上萬的交易,這意味着這將被稱爲數千次,儘管它只與第一筆交易有關。

從一般意義上講,實現回調的優雅方式是什麼。這似乎凌亂?

+0

我認爲這歸結爲階級責任問題。由合同決定是否存在或不存在;所以通過合約實例創建所有交易,然後標記它;或者根本不記錄'is_live'布爾值,只需定義is_live?作爲transactions.limit(1).count> 0(或更有效的替代方案) – struthersneil

+1

那麼,您是否一次創建了數千個事務(在一次Rails請求期間)?如果沒有,那麼你不應該擔心額外的1或2個查詢。 –

+0

@DavidGrayson是的,這是我沒有得到的部分 – Damien

回答

4
class Contract < ActiveRecord::Base 
    has_many :transactions 

    def mark_as_live 
    update(is_live: true) unless is_live? 
    end 
end 

class Transaction < ActiveRecord::Base 
    belongs_to :contract 

    after_create :mark_contract_as_live 

private 

    def mark_contract_as_live 
    contract.mark_as_live 
    end 
end 

這是Contract類責任,關心,如果合同應該註明直播與否。 Transaction類不應該處理這個。所以我在Contract類中創建了一個mark_as_live,並在Transactionafter_create回調中調用它。

我寧願使用保護條款的mark_as_live方法,像這樣:

def mark_as_live 
    return if is_live? 

    update(is_live: true) 
end 

但因爲它是一個很短的方法,它可能不值得。

還要注意ActiveRecord爲布爾型字段添加了像xxx?這樣的方法。該方法結尾處的問號更清楚地表達您想說的內容。

最後,但這是一個味道的問題,我不喜歡用is_xxx前綴我的布爾屬性。我不使用RSpec,可能是錯誤的,但我認爲它爲xxx屬性添加了一些謂詞匹配器,如be_xxx,它可能會與is_xxx屬性變得很奇怪。因爲很多人使用RSpec,它可能會變成一個慣例。

如果合同有成千上萬的交易,這意味着這將被稱爲數千次,儘管它只與第一筆交易有關。

如果您創建如下所示的事務,Contract實例仍將被加載:contract.transactions.create(transaction_params)。所以撥打is_live?將免費,您不必擔心。

+0

注意,你不需要守衛子句,因爲如果屬性沒有改變,ActiveRecord不會打擾持久。 – lobati