如何重构这套笨拙的if语句?

时间:2018-12-02 23:22:00

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

我有下面的代码可以工作,但是我希望它更加干燥和优雅。感觉很丑,有很多代码味道。

理想情况下,我也不想使用CASE语句,因为那样也不太红宝石。

if @property_status.eql? :rent
  if @property_type.eql? :residential
    @results = @search.results.for_rent.residential.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)
  elsif @property_type.eql? :commercial
    @results = @search.results.for_rent.commercial.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)
  else
    @results = @search.results.for_rent.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)
  end
elsif @property_status.eql? :sale
  if @property_type.eql? :residential
    @results = @search.results.for_sale.residential.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)
  elsif @property_type.eql? :commercial
    @results = @search.results.for_sale.commercial.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)
  else
    @results = @search.results.for_sale.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)
  end
else
  @results = @search.results.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)
end

有想法吗?

2 个答案:

答案 0 :(得分:4)

首先认识到这一点:

@results = @search.results.for_rent.residential.order("#{ @sort_by } #{ @sort_order }").all.paginate(page: @page, per_page: @per_page)

等效于:

@results = @search.results
@results = @results.for_rent
@results = @results.residential
@results = @results.order(@sort_by => @sort_order).paginate(page: @page, per_page: @per_page)

假设@sort_by@sort_order始终是设置好的。重要的是,您可以逐段构建查询,然后根据实例变量选择要添加的段。您可以添加几个简单的助手:

def add_property_status_to(query)
  case @property_status
  when :rent, :sale
    query.public_send("for_#{@property_type}")
  else
    query
  end
end

def add_property_type_to(query)
  case @property_type
  when :residential, :commercial
    query.public_send(@property_type)
  else
    query
  end
end

然后说这样的话:

query = @search.results
query = add_property_status_to(query)
query = add_property_type_to(query)

@results = query.order(@sort_by => @sort_order).paginate(page: @page, per_page: @per_page)

您可以将add_property_status_toadd_property_type_to方法视为本地一次性使用范围。如果您需要在多个地方使用它们,则可以使它们成为@search.results上的类方法,并说出类似这样的话:

query = @search.results
query = query.with_property_status(@property_status)
query = query.with_property_type(@property_type)

@results = query.order(@sort_by => @sort_order).paginate(page: @page, per_page: @per_page)

答案 1 :(得分:2)

我没有对其进行测试,但我认为符合以下要求:

def results
  return results_for_rent if for_rent?
  return results_for_sale if for_sale?
  default_results
end

def for_rent?
  @property_status.eql? :rent
end

def for_sale?
  @property_status.eql? :sale
end

def default_results
  @results = @search.results.order("#{ @sort_by } #{ @sort_order 
   }").all.paginate(page: @page, per_page: @per_page)
end

def results_for_rent
  if [:residential, :commercial].includes?(@property_type)
    results(@property_type, type: :for_rent)
    return 
  end
  @results = @search.results.for_rent.commercial.order("#{ @sort_by } #{ 
  @sort_order }").all.paginate(page: @page, per_page: @per_page)
end

def results_for_sale
  if [:residential, :commercial].includes?(@property_type)
    results(kind, type: :for_sale)
    return
  end
  @results = @search.results.for_sale.order("#{ @sort_by } #{ @sort_order 
  }").all.paginate(page: @page, per_page: @per_page)
end

def results(kind:, type: )
  @results = @search.results.send(kind).send(type).order("#{ @sort_by } #{ 
  @sort_order }").all.paginate(page: @page, per_page: @per_page)
end

您也可以重构.all.pagination部分,该部分相同,但是您可以理解。您还可以通过添加一个参数来重构results_for_rentresults_for_sale方法