如何干掉if else Ruby函数?

时间:2013-02-28 17:39:20

标签: ruby ruby-on-rails-3 ruby-on-rails-3.1 ruby-on-rails-3.2

如何重构这些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行是否可以以某种方式进行干扰。谢谢你的帮助!

这些是我的模特:

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

3 个答案:

答案 0 :(得分:4)

我认为你需要重新考虑一下你的设计。你有至少四个不同班级的小时费率,这有点乱。我知道你试图根据可以被更多本地化的类重写的关联来分配默认值,但是你正在做任何类的所有重写(几乎肯定不是应该负责它的类)。

person:如果一个人有特定的小时费率,那么,取得该费用,否则,获得该组织的每小时费率。此逻辑属于Person类,在公共接口中有一个方法,允许您在一个步骤中查询,例如person.real_hourly_rate。您可以使用project执行相同的操作。

最后,如果您的类具有良好的,定义良好的api,您应该能够将此方法定义为:

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

在这里,目的很清楚,这项工作是在需要的类中分配的,并且任何拿起代码的人都可以理解和理解该方法。

有一个名为delegate的方便的rails方法可能会帮助你解决一些问题:

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方法(也许这不是它的最佳名称)将为您提供小时费率(如果存在),如果不存在,则会询问相关人员的小时费率。

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

答案 2 :(得分:0)

与Java等人不同,Ruby &&||返回其中一个或另一个参数。这可以用来使具有一系列空检查的代码非常简洁:

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