在多个参数之后搜索Ruby on Rails

时间:2015-03-18 09:21:48

标签: ruby-on-rails ruby search

我对Ruby on Rails很新,并尝试创建一个允许用户同时搜索多个参数的搜索功能;来自和。要记住的是,在开发过程中可能会有更多的参数。我在搜索其中一个字段时已经开始工作,但不会超过这个。

搜索视图:

<%= form_tag(journeys_path, :method => "get", from: "search-form") do %>
    <%= text_field_tag :search_from, params[:search_from], placeholder: "Search from", :class => 'input' %>
    <%= text_field_tag :search_to, params[:search_to], placeholder: "Search to", :class => 'input' %>
    <%= submit_tag "Search", :class => 'submit' %>
  <% end %>

方法:

class Journey < ActiveRecord::Base
  def self.search(search_from)
    self.where("from_place LIKE ?", "%#{search_from}%")
  end
end

控制器:

class JourneysController < ApplicationController

  def index
    @journeys = Journey.all
      if params[:search_from]
        @journeys = Journey.search(params[:search_from])
      else
        @journeys = Journey.all.order('created_at DESC')
    end
  end

  def search
    @journeys = Journey.search(params[:search_from])
  end
end

我已尝试过一些宝石和我在其他问题中找到的所有解决方案,但我对RoR还不够好,但在没有帮助的情况下成功地正确应用它们。我很感激能得到的任何帮助。

谢谢!

2 个答案:

答案 0 :(得分:0)

型号:

class Journey < ActiveRecord::Base
  def self.search(search_from, search_to)
    self.where("from_place LIKE ? and to_place LIKE ?", "%#{search_from}%", "%#{search_to}%")
  end
end

控制器:

class JourneysController < ApplicationController

  def index
      if params[:search_from] and params[:search_to]
        @journeys = search
      else
        @journeys = Journey.all.order('created_at DESC')
    end
  end

  def search
    @journeys = Journey.search(params[:search_from], params[:search_to])
  end
end

答案 1 :(得分:0)

这里最好的方法是将搜索表单封装为单独的Ruby类。在这里使用Virtus有助于免费获得类型强制。

class SearchForm
  include Virtus.model # Our virtus module
  include ActiveModel::Model # To get ActiveRecord-like behaviour for free.

  attribute :from, String
  attribute :to, String

  # Just to check if any search param present, 
  # you could substitute this with validations and just call valid?
  def present?
    attributes.values.any?{|value| value.present?}
  end

```

在Rails 3 IIRC中,您还必须包含ActiveModel :: Validations,以便在需要时验证表单输入。 现在,让我们看看如何重构控制器。我们从params实例化form对象并将其传递给模型查询方法以获取所需的记录。我还移动了if子句的命令,并使用符号排序参数 - 更清洁的IMO。

def index
  @search_form = SearchForm.new(search_params)
  if @search_form.valid? && @search_form.present?
    @journeys = Journey.search(@search_form)
  else
    @journeys = Journey.all
  end
  @journeys = @journeys.order(created_at: :desc)
end

def search
  @journeys = Journey.search(SearchForm.new(search_params)
end

private
def search_params
  params.require(:search_form).permit(:from, :to)
end

现在到视图:form_for将与我们的表单对象完美配合,simple_form_for

也是如此
<%= form_for @search_form, url: journeys_path, method: :get do |f| %>
  <%= f.text_field :from, placeholder: "Search from", class: 'input' %>
  <%= f.text_field :to, placeholder: "Search to", class: 'input' %>
  <%= f.submit "Search", class: 'submit' %>
<% end %>

查看现在看起来更短更清洁。在对象中包含params使搜索参数更容易处理。

型号:

class Journey < ActiveRecord::Base
  def self.search(search_form)
    if search_form.kind_of?(SearchForm)
      journeys = all # I'm calling Journey.all here to build ActiveRecord::Relation object
      if search_form.from.present?
        journeys = journeys.where("from_place LIKE ?", "%#{search_form.from}%")
      end
      if search_form.to.present?
        journeys = journeys.where("to_place LIKE ?", "%#{search_form.to}%")
      end
    else
      raise ArgumentError, 'You should pass SearchForm instance to Journey.search method'
    end
  end
end

注意我如何通过调用Journeys.all并应用每个搜索参数(如果存在)来构建ActiveRecord :: Relation对象。像这样链接where会自动将AND置于其中,如果需要OR,Rails 4会将其Journey.or(condition)。{{1}}。 这种方法的优点:

  1. 你正在使用Plain Old Ruby Classes,这里几乎没有魔法,它在许多方面像普通的Rails模型一样工作。将搜索参数放在对象中使得重构代码变得容易得多。 Virtus是唯一的依赖,当然没有Rails本身,它更方便和避免编写无聊的样板代码。
  2. 如果需要,您可以轻松验证输入(如果您真的想严格控制输入并显示用户验证错误,而不是静默执行具有矛盾条件的愚蠢查询并且不返回任何结果)。