Как я могу упростить условия, когда у меня много параметров в моем поиске?

Например

У меня есть 5 параметров в моем представлении поиска:

  params[:a]       params[:b]       params[:c]       params[:d]       params[:e]

И я хочу искать в своем контроллере, когда:

  params[:a].present? and params[:b].nil?
  params[:a].present? and params[:c].nil?
  params[:a].present? and params[:e].nil?
  params[:b].present? and params[:c].nil?
  params[:b].present? and params[:d].nil?
   ............
  params[:a].nil? and params[:b].nil?
  .............

Вот что я пробовал:

 controller: 

 if params[:a].nil?
    @query
 else
    if params[b].nil?
      @another_query
    else
      ...........#and it will continue with lots of conditions according with params
    end
 end

Ну, есть много условий, которые я могу попробовать

Вот, используя реальный пример, я получил эту ошибку «неопределенный метод «paginate» для nil: NilClass»

 #table
 policies
   id   num_policy   type_id    doc    name
    1        2323      1       181844  Charles
    2        2121      2       151511  Aguardientico
    3        3423      2       434344  Benjamin

 #controller

if params[:num_policy].present?
  @search= Policy.find(:all,:conditions=>['num_policy LIKE ?',params[:num_policy] ])
end

if params[:type_id].present?
  @search= Policy.find(:all,:conditions=>['type_id LIKE ?',params[:type_id] ])
end

if params[:doc].present?
  @search= Policy.find(:all,:conditions=>['doc LIKE ?',params[:doc] ])
end

if params[:name].present?
  @search= Policy.find(:all,:conditions=>['name LIKE ?',params[:name] ])
end

if params[:doc].present? and params[:type_id].present?
  @search= Policy.find(:all,:conditions=>['doc LIKE ? and type_id LIKE ?',params[:doc],params[:type_id] ])
end

@policies= @search.paginate( :page => params[:page], :per_page =>2)

#view

<% form_tag :controller=>"policy",:action=>"search" do %>
   <%= text_field_tag "num_policy",params[:num_policy] %>
   <%= text_field_tag "doc",params[:doc] %
   <%= text_field_tag "name",params[:name] %
   <%= text_field_tag "type_id",params[:type_id] %
<% end %> 

 <% @policies.each do |p| %>
   <%= p.num_policy %>
   <%= p.type_id %>
   <%= p.doc %>
   <%= p.name %>
 <% end %>

Но если удалить paginate, я получил эту ошибку: «У вас есть нулевой объект, когда вы этого не ожидали! Возможно, вы ожидали экземпляр Array. Ошибка произошла при оценке nil.each»

 #controller
 @policies= @search

 #says that my line  <% @policies.each do |p| %>  is nil

Есть ли способ их контролировать?

Пожалуйста, я просто хочу мнения, может быть, у кого-то это тоже было ..

Спасибо.


person Carlos Morales    schedule 21.11.2013    source источник
comment
Вы имеете в виду, когда любая из этих строк верна?   -  person Tamer Shlash    schedule 22.11.2013
comment
не совсем верно или ложно, я имею в виду, имеет ли значение или оно пусто (присутствует и пусто)   -  person Carlos Morales    schedule 22.11.2013


Ответы (3)


@search = Policy.scoped
@search = @search.where('num_policy LIKE ?', params[:num_policy]) if params[:num_policy].present?
@search = @search.where('type_id LIKE ?', params[:type_id]) if params[:type_id].present?
@search = @search.where('doc LIKE ?', params[:doc]) if params[:doc].present?
@search = @search.where('name LIKE ?', params[:name]) if params[:name].present?
@policies = @search.paginate(page: params[:page], per_page: 2)

Кстати: проблема в том, что вы создаете @search внутри операторов if, поэтому, если параметры не существуют, @search не существует.

Это версия рельсов 2:

conditions_str = []
conditions_values = {}
['num_policy', 'type_id', 'doc', 'name'].each do |cond|
  if params[cond.to_sym].present?
    conditions_str << "#{cond} LIKE :#{cond}"
    conditions_values[cond.to_sym] = params[cond.to_sym]
  end
end
@policies = Policy.find(:all, :conditions => [conditions_str.join(" AND "), conditions_values])
person Aguardientico    schedule 21.11.2013
comment
а как в контроллере или во вьюхе?? у вас есть пример? - person Carlos Morales; 22.11.2013
comment
Это пример, если вам нужно передать результат от контроллера для просмотра, измените result на @result - person Aguardientico; 22.11.2013
comment
Aguardientico, я отредактировал сообщение и добавил более подробную информацию об условиях, вы знаете, как это исправить? - person Carlos Morales; 23.11.2013
comment
@CarlitosMorales: я снова обновил ответ, чтобы использовать ваш пример, попробуйте - person Aguardientico; 23.11.2013
comment
OMG действительно очень спасибо, что вы сделали это, вы поняли и помогли очень хорошо. Большое спасибо - person Carlos Morales; 23.11.2013
comment
рад, что могу вам помочь :) - person Aguardientico; 23.11.2013

Вам нужно очистить свои параметры и извлечь хэш только с вашими критериями поиска, тогда вы можете написать простые для чтения условия. Пример:

# define what are the search keys that can be found in params[]
search_keys = [:a, :b, :c, :d, :e, :f]

# extract hash values that concern only the search criteria
search_params = params.select { |k,v| search_keys.include? k and ! v.nil? and ! v.empty? }

# Write query according to search criteria presents
case search_params.keys.sort
  when [:a]
    # Write the query when only :a search criteria is present
    Something.where("blahblah = ?", params[:a])
  when [:a, :c]
    # Write the query when only :a and :c search criteria are present
    Something.where("a_field = ? AND stuff = ?", params[:a], params[:c])
  when ...
    ...
end
person Benj    schedule 22.11.2013
comment
Вы знаете, как это влияет на PAGINATE?? - person Carlos Morales; 22.11.2013
comment
, я отредактировал сообщение и добавил более подробную информацию об условиях, вы знаете, как это исправить? - person Carlos Morales; 23.11.2013
comment
Бенджамин, ты понял, чего я хочу, как я могу это сделать, используя рельсы 2? Не могли бы вы мне помочь? - person Carlos Morales; 23.11.2013

Я не знаю, правильно ли я понял ваш вопрос, но я все равно опубликую свой ответ.

Я бы сделал функцию:

def simplified_conditions conds, prms, perform_and_on_hashes = false
  conds.each do |h|
    h.each do |method_name, symbols_array|
      symbols_array.each do |symb|
        return false unless prms[symb].send method_name
      end
    end
    return true unless perform_and_on_hashes
  end
  return true
end

И передайте ему структуру условий, которая выглядит так:

[
  { 'boolean_function_name' => [:array,:of,:symbols],
    'another_function_name' => [:array,:of,:symbols],
    'another_function_name' => [:array,:of,:symbols]
  },
  { 'boolean_function_name' => [:array,:of,:symbols],
    'another_function_name' => [:array,:of,:symbols],
    'another_function_name' => [:array,:of,:symbols]
  },
  { 'boolean_function_name' => [:array,:of,:symbols],
    'another_function_name' => [:array,:of,:symbols],
    'another_function_name' => [:array,:of,:symbols]
  }
]

Итак, в ваших примерных условиях массив будет выглядеть так:

conds = [
  { 'present?' => [:a], 'nil?' => [:b] },
  { 'present?' => [:a], 'nil?' => [:c] },
  { 'present?' => [:a], 'nil?' => [:e] },
  { 'present?' => [:b], 'nil?' => [:c] },
  { 'present?' => [:b], 'nil?' => [:d] }
]

# And then to call it:
final_boolean_result = simplified_conditions(conds, params, false)

Это вернет true, если любая из строк в вашем примере верна. Если вы хотите, чтобы ВСЕ они были правдой, просто измените последний параметр на true.

Если я неправильно понял ваш вопрос, пожалуйста, оставьте комментарий.

person Tamer Shlash    schedule 21.11.2013
comment
, я отредактировал сообщение и добавил более подробную информацию об условиях, вы знаете, как это исправить? - person Carlos Morales; 23.11.2013