Rails 5.1,代码改进,搜索查询(范围),按日期和过滤器

时间:2018-01-27 07:36:11

标签: ruby-on-rails search filter scope ruby-on-rails-5

我正在构建一个rails应用程序,我有一个使用范围的搜索查询。代码正在运行,但我很确定它不是最好的方式,如果我想添加一些东西,我想在未来中提高它的可靠性。

这是我的观点:

<%= form_tag spendings_path, method: :get do %>
  <%= date_field_tag "search[date_from]", @search.date_from, class: 'form-control col-2 d-inline-block' %>
  <%= date_field_tag "search[date_to]", @search.date_to, class: 'form-control col-2 d-inline-block' %>
  <%= select_tag "search[user_id]", options_from_collection_for_select(User.all, :id, :firstname, params[:user_id]), include_blank: "All Users", class: 'form-control col-2 d-inline-block' %>
  <%= select_tag "search[currency_id]", options_from_collection_for_select(Currency.all, :id, :name, params[:currency_id]), include_blank: "All Currencies", class: 'form-control col-2 d-inline-block' %>
  <%= submit_tag "Search", name: nil, class: "btn btn-secondary d-inline-block" %> <%= link_to "Reset", spendings_path, class: "btn btn-secondary d-inline-block" %>
<% end %>

在这里,我正在刷新页面以“重置”过滤器。这是一个不错的选择吗? 我的控制器:

@search = SpendingSearch.new(params[:search])

我的帮手:

@search.scope.order('date DESC').paginate(:page => params[:page], :per_page => 10)

最后我的模型只为此搜索目的而创建:

class SpendingSearch
  attr_reader :date_from, :date_to, :user_id, :currency_id  

  def initialize(params)
    params ||= {}
    @date_from = parsed_date(params[:date_from], 1.month.ago.to_date.to_s)
    @date_to = parsed_date(params[:date_to], Date.tomorrow.to_s)
    @user_id = params[:user_id]
    @currency_id = params[:currency_id]
  end

  def scope
    if @user_id.present? && @currency_id.present?
      Spending.where("date BETWEEN ? AND ? AND user_id = ? AND currency_id = ?", @date_from, @date_to, @user_id, @currency_id)
    elsif @user_id.present?
      Spending.where("date BETWEEN ? AND ? AND user_id = ?", @date_from, @date_to, @user_id)
    elsif @currency_id.present?
      Spending.where("date BETWEEN ? AND ? AND currency_id = ?", @date_from, @date_to, @currency_id)
    else
      Spending.where("date BETWEEN ? AND ?", @date_from, @date_to)
    end
  end

  private

  def parsed_date(date_string, default)
    Date.parse(date_string)
  rescue ArgumentError, TypeError
    default
  end        
end

正如你所看到的,最糟糕的是......这个范围有点荒谬。

基本上我正在寻找datesuser_idcurrency_id。如果currency_iduser_id留空(因为我在视图中包含空白),我希望结果显示所有user_idcurrency_id

我确信有更好的方法可以做到这一点,我只是不知道它可能是哪一种。

同样,我知道这是给我代码的重点,我只是想在这里改进,所以任何类似的东西,也许你应该检查一下,或者这里有一个可以帮助非常好的链接。

也许我应该改变一切,我只是不知道,我不是铁杆专家,任何提示,技巧或提示都非常感激。

非常感谢。

1 个答案:

答案 0 :(得分:0)

请尝试以下scope方法:

def scope
  s_scope = Spending.where('date BETWEEN ? AND ?', @date_from, @date_to)
  s_scope = s_scope.where(user_id: @user_id) if @user_id.present?
  s_scope = s_scope.where(currency_id: @currency_id) if @currency_id.present?

  s_scope
end

另外,我相信你可以改变:

@date_from = parsed_date(params[:date_from], 1.month.ago.to_date.to_s)
@date_to = parsed_date(params[:date_to], Date.tomorrow.to_s)

@date_from = parsed_date(params[:date_from], 1.month.ago.to_date)
@date_to = parsed_date(params[:date_to], Date.tomorrow)