使用搜索查询的范围

Using scopes for search queries

我正在努力通过使用模型改进我的应用程序中的搜索功能。

这是我到目前为止一直在使用的:

searchController#index:

def index
    # Enable display of results page on direct access with no params
    return false if params[:s].nil?

    # Venues near search location using Lon/Lat and Geocoder
    @venues = Venue.near eval(params[:s]["geo"])

    # Search variables
    near_by_venues = @venues.to_a.map(&:id)
    s_activity = params[:s]["activity"].to_i
    s_start_time = (params[:s]["start_time"]).to_datetime
    s_end_time = (params[:s]["end_time"]).to_datetime

    # Filter availabilities based on search criteria
    @search = Availability.includes{facility.activities}
            .where{
              (facility.venue_id.in near_by_venues)
            }
            .where{
              (activities.id == s_activity) &
              (booking_id == nil) &
              (start_time >= s_start_time ) &
              (end_time <= s_end_time )
            }
            .order{start_time.desc}
            .references(:all)
end

到目前为止,这对我来说效果很好,但我开始考虑搜索的其他用例,例如可选参数或默认参数(如果出于某种原因未提供位置或未指定 start/end 时间) .这让我看到了有关范围搜索的文章,其中所有内容都在模型级别而不是控制器级别进行处理。

我在我的 Availability 模型中创建了这些范围:

class Availability < ActiveRecord::Base
  # Associations
  belongs_to :facility
  belongs_to :booking

  #  Scopes for search filters
  scope :close_to, -> (locations) { where{facility.venue_id.in locations} }
  scope :activity,  -> (activity) {where {activities.id == activity}}
  scope :start_date, -> (datetime) {where{created_at >= datetime}}
  scope :end_date, -> (datetime) {where{created_at <= datetime}}
  scope :not_booked, -> {where(booking: nil)}
  scope :order, -> {order{start_time.desc}}
end

我无法将它们放在一起。我不确定如何在模型中包含我 includes{facility.activities} 的连接,所以当我做类似 Availability.activity(5).not_booked 的事情时,它会 returns 正确。

您可以按以下方式 include availability 中的 activity

scope :activity, -> (activity) { includes({facility: :activities}).where{activities.id == activity}.references(:all) } 

有很多方法可以做到这一点,但为了简单起见,我将这些事情放在一个关注点中。例如 AvailabilitySearch,在 app/models/concerns

在可用性中,您将其包括在内

class Availability < ActiveRecord::Base

  include AvailabilitySearch

end

那么,在这里,你可以为所欲为。

module AvailabilitySearch

  extend ActiveSupport::Concern

  module ClassMethods

    def search(params)
      results = self.includes(:relation_that_is_always_referenced)

      # use scopes or not
      results = results.where(:key => params[:key]).includes(:relation_that_is_sometimes_referenced) if params[:key]
      results = results.activity(params[:activity) if params[:activity]
      ...

      # and then return your results
      return results
    end
  end
end

最后一件事,将一些 javascript 添加到搜索页面以删除 url 中的所有空白输入,这样它就干净了,如果共享也有意义。

在 coffeescript 中,给定搜索表单的 ID 为 'search_form'

$(document).on 'ready page:load', ->
  $('#search_form').submit ->
    $(this).find(':input').filter(->
      !@value
    ).prop 'disabled', true
    true

  # If they hit back
  $('#search_form').find(':input').prop 'disabled', false

  # If they stop and click on the form again
  $('#search_form').on 'click', ->
    $(this).find(':input').prop 'disabled', false

  return