2012-10-07 79 views
0

我想簡化這個複雜的邏輯來創建獨特的Track對象。如何在create_unique方法中重構複雜的邏輯?

def self.create_unique(p) 
    f = Track.find :first, :conditions => ['user_id = ? AND target_id = ? AND target_type = ?', p[:user_id], p[:target_id], p[:target_type]] 
    x = ((p[:target_type] == 'User') and (p[:user_id] == p[:target_id])) 
    Track.create(p) if (!f and !x) 
end 

回答

2

這裏有幾個簡單的方法提取一個重寫:

def self.create_unique(attributes) 
    return if exists_for_user_and_target?(attributes) 
    return if user_is_target?(attributes) 

    create(attributes) 
end 

def self.exists_for_user_and_target?(attributes) 
    exists?(attributes.slice(:user_id, :target_id, :target_type)) 
end 

def self.user_is_target?(attributes) 
    attributes[:target_type] == 'User' && attributes[:user_id] == attributes[:target_id] 
end 

這重寫顯示我的少,描述方法的偏好,以幫助解釋意圖。我還喜歡在create_unique等情況下使用警衛子句;在最後一行(create(attributes))中顯示了幸福的路徑,但警衛清楚地描述了特殊情況。我相信我在exists_for_user_and_target?中使用exists?可能是find :first的一個很好的替代品,儘管它假定了Rails 3.

您也可以考慮使用唯一性主動模型驗證。

-1
@@keys = [:user_id, :target_id, :target_type] 
def self.create_unique(p) 
    return if Track.find :first, :conditions => [ 
    @@keys.map{|k| "#{k} = ?"}.join(" and "), 
    *@@keys.map{|k| p[k]} 
    ] 
    return if p[@@keys[0]] == p[@@keys[1]] 
    return if p[@@keys[2]] == "User" 
    Track.create(p) 
end