【问题标题】:Rails 5.1, code improvement, search query (scope), by date and filtersRails 5.1,代码改进,搜索查询(范围),按日期和过滤器
【发布时间】:2018-07-06 12:29:46
【问题描述】:

我正在构建一个 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

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

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

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

非常感谢。

【问题讨论】:

  • 好的,这意味着当前代码可以正常搜索?对吗?
  • 目前它工作得很好,是的。我会说这只是写得不好:)

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


【解决方案1】:

请尝试以下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)

【讨论】:

  • 我试了代码,spending_scope 没有定义。我尝试用 Spending.where 更改它,但看起来如果我按日期、用户和货币搜索它会显示所有内容
  • 好吧,不……我的错,我改成了这样:s_scope.where(user_id: @user_id) if @user_id.present?。看起来它有效,我会尝试更多。谢谢你的回答
  • 抱歉,我已将支出范围更改为 s_scope 以缩短语句,但忘记全部替换。我已经修正了错误。
  • 就是这样,是的。非常感谢你。它好多了,我学到了一些新东西。谢谢@Tai!
猜你喜欢
  • 2018-06-29
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 2010-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多