如何在create_unique方法中重构复杂的逻辑?

时间:2012-10-07 00:37:36

标签: ruby-on-rails ruby ruby-on-rails-3 refactoring

我想简化这个复杂的逻辑来创建独特的Track对象。

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 个答案:

答案 0 :(得分: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?中使用exists_for_user_and_target?可能是find :first的一个很好的替代品,尽管它假设Rails 3。

您也可以考虑使用唯一性主动模型验证。

答案 1 :(得分:-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