在控制器动作中重构params [...]的许多if语句

时间:2011-09-25 20:01:09

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

我有这样的代码,用于在我的表单中进行链选择 查看索引操作:

<%= form_tag do %>
    <%= collection_select(*@brands_select_params) %>
    <%= collection_select(*@car_models_select_params) %>
    <%= collection_select(*@production_years_select_params) %>
    <% # Пока еще никто ничего не выбрал %>
<%= submit_tag "Send", :id => "submit", :name => "submit" %>

我的控制员:

class SearchController < ApplicationController
  def index
    @brands = Brand.all
    @car_models = CarModel.all

    if (params[:brand].blank?)
      @brands_select_params = [:brand, :id, @brands, :id, :name, :prompt => "Выбирай брэнд"]

      if params[:car_model].blank?
        @car_models_select_params = [:car_model, :id, @car_models, :id, :name, { :prompt => "Model" }, \
                                   { :disabled => "disabled" }]
        @production_years_select_params = [:production_year, :id, @car_models, :id, :name, { :prompt => "Year" }, \
                                         { :disabled => "disabled" }]
      end
    else
      @brands_select_params = [:brand, :id, @brands, :id, :name, { :selected => params[:brand][:id] } ]
      if params[:car_model].blank?
        @car_models_select_params = [:car_model, :id, Brand.find(params[:brand][:id]).car_models, :id, :name, \
                                   { :prompt => "And model now" } ]
        @production_years_select_params = [:production_year, :id, @car_models, :id, :name, { :prompt => "Year" }, \
                                         { :disabled => "disabled" } ]
      else
        @car_models_select_params = [:car_model, :id, Brand.find(params[:brand][:id]).car_models, :id, :name, \
                                   { :selected => params[:car_model][:id] } ] unless params[:car_model][:id].empty?
        @production_years_select_params = [:production_year, :id, CarModel.find(params[:car_model][:id]).production_years, :id, :year, \
                                         { :prompt => "And year now" } ] unless params[:car_model][:id].empty?
      end
    end
  end
end

如您所见,我的控制器代码中有太多ifs。我会在那里添加更多条件。之后,任何阅读该代码的人都会受到脑损伤。所以我只想以真正的Ruby方式制作它,但不知道如何。伙计们,请帮忙。我应该如何重构这一堆废话?

2 个答案:

答案 0 :(得分:5)

我认为问题的一大部分是你在控制器中做得太多了。应该在视图和视图助手中完成生成标记(以及包括为表单助手构建参数列表的IMO)。所以:

module SearchHelper
  def brand_select brands, options={}
    collection_select :brand, :id, brands, :id, :name, :options
  end

  def car_model_select car_models, options={}
    collection_select :car_model, :id, car_models, :id, :name, options
  end

  def production_year_select years, options={}
    collection_select :production_year, :id, years, :id, :year, options
  end
end

然后你可以将你的控制器切到这个:

def index
  @brands     = Brand.all
  @car_models = CarModel.all

  @selected_brand_id      = params[:brand]      && params[:brand][:id]
  @selected_car_model_id  = params[:car_model]  && params[:car_model][:id]

  @production_years = @selected_car_model_id ?
    [] : CarModel.find(@selected_car_model_id).production_years
end

在你看来:

<%= brand_select @brands, :prompt   => "Выбирай брэнд",
                          :selected => @selected_brand_id
%>
<%= car_model_select @car_models, :prompt   => "Model",
                                  :selected => @selected_car_model_id
%>
<%= production_year_select @production_years, :prompt   => "Year",
                                              :selected => @selected_car_id
%>

我怀疑你可以使用form_for and fields_for进一步简化这一点,并完全摆脱帮助者,但这取决于你的模型关联的设置方式。

答案 1 :(得分:2)

这种问题没有明显的解决方案。

通常,我会尽量保持if / else架构,并将所有代码导出到不同的方法中。这里有两个优点:

  • 可读性

  • 更容易进行单元测试

对于您的情况,它将是:

class SearchController < ApplicationController
  def index
    @brands = Brand.all
    @car_models = CarModel.all

    if (params[:brand].blank?)
      @brands_select_params = [:brand, :id, @brands, :id, :name, :prompt => "Выбирай брэнд"]
      if params[:car_model].blank?
        @car_models_select_params, @production_years_select_params =  get_card_model(@car_models)
      end
    else
      @brands_select_params = [:brand, :id, @brands, :id, :name, { :selected => params[:brand][:id] } ]
      if params[:car_model].blank?
        @car_models_select_params, @production_years_select_params = foo_method(@car_models)
      else
        @car_models_select_params, @production_years_select_params = bar_method
      end
    end
  end

  def get_card_model car_models
   [
    [:car_model, :id, car_models, :id, :name, { :prompt => "Model" }, { :disabled => "disabled" }],
    [:production_year, :id, car_models, :id, :name, { :prompt => "Year" }, { :disabled => "disabled" }]
    ]
  end
end