0

このちょっとした Ruby コードをリファクタリングして見苦しくないようにするにはどうすればよいでしょうか。

def default_item_price(user)
  if project.present?
    if project.hourly_rate?
      project.hourly_rate
    elsif project.person.hourly_rate?
      project.person.hourly_rate
    elsif project.person.organisation && project.person.organisation.hourly_rate?
      project.person.organisation.hourly_rate
    else
      user.preference.hourly_rate     
    end
  else
    user.preference.hourly_rate
  end
end

私は Ruby プログラミングをあまりやったことがないので、最後の 6 行をどうにかして DRY できるのではないかと考えています。助けてくれてありがとう!

これらは私のモデルです:

class User
  has_many :people
end

class Person
  belongs_to :user
  has_many :projects

  def real_hourly_rate
    hourly_rate || organisation.real_hourly_rate
  end    
end

class Project
  belongs_to :person
  has_many :invoices

  def real_hourly_rate
    hourly_rate || person.real_hourly_rate
  end
end

class Invoice
  belongs_to :project

  def default_item_price(user)
    project.real_hourly_rate || user.preference.hourly_rate    
  end
end
4

3 に答える 3

4

デザインを少し考え直す必要があると思います。少なくとも4つの異なるクラスで時給がありますが、これは少し混乱しています。よりローカライズされたものによってオーバーライドできる関連付けに基づいてデフォルト値を割り当てようとしていることを理解していますが、これがどのクラスであっても(ほとんどの場合、それを担当するクラスではありません)、すべてのオーバーライドを実行しています。

取るperson:人が特定の時給を持っている場合はそれを取得し、そうでない場合はその人の組織の時給を取得します。このロジックはPersonクラスに属し、パブリックインターフェイスのメソッドを使用して、これを1つのステップでクエリできますperson.real_hourly_rate。で同じようなことができますproject

最終的に、クラスに適切に定義されたAPIがある場合は、このメソッドを次のように定義できるはずです。

def default_item_price(user)
  project_hourly_rate || user.preference_hourly_rate
end

ここでは、意図が明確であり、うなり声の作業が必要なクラスに分散されており、コードを取得した人なら誰でもメソッドを読みやすく理解できます。

これのいくつかであなたを助けるかもしれないと呼ばれる便利なレールメソッドがdelegateあります:

class Project
  delegate :hourly_rate, to: :person, prefix: true, allow_nil: true

  def real_hourly_rate
    hourly_rate || person_hourly_rate
  end

このreal_hourly_rate方法(おそらくそれはそれの最良の名前ではありません)は、存在する場合は時給を提供し、存在しない場合は、関係者に時給を尋ねます。

于 2013-02-28T17:56:31.667 に答える
1

私はザックに同意します。とにかくドライヤーの書き直しです!

def hourly_rate_from anything
  anything.hourly_rate? ? anything.hourly_rate : nil
end

def default_item_price user
  if project.present?
    rate = hourly_rate_from project
    rate ||= hourly_rate_from project.person
    if project.person.organisation
      rate ||= hourly_rate_from( project.person.organisation ) 
    end
    return rate if rate
  end
  hourly_rate_from user.preference
end
于 2013-02-28T17:59:45.367 に答える
0

Java et alとは異なり、Rubyでは、引数のいずれか&&を返します。||これを使用して、一連のnullチェックを含むコードを非常に簡潔にすることができます。

def default_item_price(user)
  if project.present?
    project.hourly_rate ||
    project.person.hourly_rate ||
    (project.person.organisation && project.person.organisation.hourly_rate) ||
    user.preference.hourly_rate
  else
    user.preference.hourly_rate
  end
end
于 2013-02-28T18:46:44.520 に答える