重构可选参数方法以删除`if`语句

时间:2015-12-15 04:13:30

标签: ruby-on-rails ruby optional-parameters

我有一个方法select_active_buildings,其中有三个参数,默认为nil,可以使用提供的信息过滤我的数据库。

def select_active_buildings(category:nil, upgrader:nil, upgrade_resource:nil)
  my_active_buildings = self.buildings.active(self.townhall_level)
  if category && upgrader && upgrade_resource
    return my_active_buildings.where(category:category, upgrader:upgrader, upgrade_resource:upgrade_resource)
  elsif category && upgrader
    return my_active_buildings.where(category:category, upgrader:upgrader)
  elsif category && upgrade_resource
    return my_active_buildings.where(category:category, upgrade_resource:upgrade_resource)
  elsif upgrader && upgrade_resource
    return my_active_buildings.where(upgrader:upgrader, upgrade_resource:upgrade_resource)
  elsif category
    return my_active_buildings.where(category:category)
  elsif upgrader
    return my_active_buildings.where(upgrader:upgrader)
  elsif upgrade_resource
    return my_active_buildings.where(upgrade_resource:upgrade_resource)
  else
    return my_active_buildings
  end
end

我需要帮助重构这种方法。

3 个答案:

答案 0 :(得分:3)

我会这样做:

def select_active_buildings(category: nil, upgrader: nil, upgrade_resource: nil)
  my_active_buildings = self.buildings.active(self.townhall_level)
  cond = {
    category: category,
    upgrader: upgrader,
    upgrade_resource: upgrade_resource
  }.select { |k, v| v }
  my_active_buildings.where(cond)
end

或者,

def select_active_buildings(category: nil, upgrader: nil, upgrade_resource: nil)
  my_active_buildings = self.buildings.active(self.townhall_level)
  cond = {}
  cond[:category] = category if category
  cond[:upgrader] = upgrader if upgrader
  cond[:upgrade_resource] = upgrade_resource if upgrade_resource
  my_active_buildings.where(cond)
end

或者,如果我不关心select_active_function级别的语法检查,

def select_active_buildings(cond)
  my_active_buildings = self.buildings.active(self.townhall_level)
  my_active_buildings.where(cond)
end

如果您真的不想要.where({})案例,可以在其前加return my_active_buildings if cond.empty?

答案 1 :(得分:2)

假设您正在使用ActiveRecord,Mongoid或其他具有可链接where的内容,您可以利用以下这一事实:

o.where(:a => b, :c => d)

与:

相同
o.where(:a => b).where(:c => d)

这可以让你这样做:

def select_active_buildings(category: nil, upgrader: nil, upgrade_resource: nil)
  buildings = self.buildings.active(self.townhall_level)
  buildings = buildings.where(category: category) if(category)
  buildings = buildings.where(upgrader: upgrader) if(upgrader)
  buildings = buildings.where(upgrade_resource: upgrade_resource) if(upgrade_resource)
  buildings
end

甚至:

def select_active_buildings(conditions)
  buildings = self.buildings.active(self.townhall_level)
  %i[category upgrader upgrade_resource]
    .select { |f| conditions.has_key?(f) }
    .inject(buildings) { |q, f| q.where(f => conditions[f]) }
end

答案 2 :(得分:-1)

def select_active_buildings(category: nil, upgrader: nil, upgrade_resource: nil)
  buildings.active(self.townhall_level).where(
    **({category: category} if category).to_h,
    **({upgrader: upgrader} if upgrader).to_h,
    **({upgrade_resource: upgrade_resource} if upgrade_resource).to_h,
  )
end