Rails:使用块

时间:2015-09-23 14:30:03

标签: ruby-on-rails ruby refactoring

我使用Rails 4.2,我想重构我的帮助方法以摆脱重复的代码:

在app / helpers / admin / tasks_helper.rb

def chosen_select(name, method, chzes, selected = nil, options = {}, html_options = {})
  options[:value_method] ||= :id
  options[:text_method] ||= :name
  if options.key?(:placeholder)
    html_options['data-placeholder'.intern] = options[:placeholder]
    options.delete(:placeholder)
  end
  if html_options.key?(:class)
    html_options[:class] = 'chosen-select ' + html_options[:class]
  else
    html_options[:class] = 'chosen-select'
  end
  chzes = options_from_collection_for_select(chzes, options[:value_method], options[:text_method], selected)
  options.delete(:value_method)
  options.delete(:text_method)
  select(name, method, chzes, options.merge!(include_hidden: false), html_options)
end

def chosen_select_array(name, method, chzes, selected = nil, options = {}, html_options = {})
  options[:value_method] ||= :id
  options[:text_method] ||= :name
  if options.key?(:placeholder)
    html_options['data-placeholder'.intern] = options[:placeholder]
    options.delete(:placeholder)
  end
  if html_options.key?(:class)
    html_options[:class] = 'chosen-select ' + html_options[:class]
  else
    html_options[:class] = 'chosen-select'
  end
  chzes = options_for_select(chzes, selected)
  options.delete(:value_method)
  options.delete(:text_method)
  select(name, method, chzes, options.merge!(include_hidden: false), html_options)
end

我的观点我有很多方法调用,比如app / views / admin / tasks / index.html.erb

  <%= chosen_select(:select, :project_id, [TaskFilterOptgroups.active_projects, TaskFilterOptgroups.inactive_projects] , @task_filter_configuration.project_id, {:include_blank => true, :placeholder => 'Project'}, {'data-last-project_id' => @task_filter_configuration.project_id, :style => 'width: 150px;'}) %>

这样我就不想在视图中更改方法调用了。 我的尝试是创建一个通用方法“chosen_select_generic”,它将从特定方法调用,如“chosen_select”:

def chosen_select_generic(name, method, chzes, selected = nil, options = {}, html_options = {})
  options[:value_method] ||= :id
  options[:text_method] ||= :name
  if options.key?(:placeholder)
    html_options['data-placeholder'.intern] = options[:placeholder]
    options.delete(:placeholder)
  end
  if html_options.key?(:class)
    html_options[:class] = 'chosen-select ' + html_options[:class]
  else
    html_options[:class] = 'chosen-select'
  end
  # 2 different chzes in 2 methods:
  # 1) chosen_select(...)
  # chzes = options_from_collection_for_select(chzes, options[:value_method], options[:text_method], selected)
  # 2) chosen_select_array(...)
  # chzes = options_for_select(chzes, selected)     
  yield chzes 
  options.delete(:value_method)
  options.delete(:text_method)
  select(name, method, chzes, options.merge!(include_hidden: false), html_options)
end

然后selected_select看起来像:

def chosen_select(name, method, chzes, selected = nil, options = {}, html_options = {})
  chosen_select_generic(name, method, chzes, selected = nil, options = {}, html_options = {}) do |contents|
    chzes = option_groups_from_collection_for_select(chzes, :entries, :status, options[:value_method], options[:text_method], selected)
  end
end

但这不起作用。如何在不更改视图中的方法调用的情况下提取块中的重复代码?

1 个答案:

答案 0 :(得分:1)

您的区块中的此分配将无法按您的意思执行:

chzes = option_groups_from_collection_for_select(...)

它创建一个新的局部变量而不是更改外部变量。如果它是这里唯一可更改的部分,那么您可以从块中返回它:

chosen_select_generic(name, method, chzes, selected = nil, options = {}, html_options = {}) do |chzes|
  option_groups_from_collection_for_select(chzes, :entries, :status, options[:value_method], options[:text_method], selected)
end

并在您的通用方法中接收如下值:

chzes = yield(chzes)