使用范围进行搜索查询

时间:2015-09-01 17:23:56

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord squeel

我正在使用模型改进我的应用中的搜索功能。

这是我到目前为止所使用的:

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

到目前为止,这对我来说效果很好,但我开始考虑搜索的其他用例,如可选参数或默认参数,如果由于某种原因没有提供位置或者没有指定开始/结束时间。这引出了一些关于范围搜索的文章,其中所有内容都是在模型级而不是控制器上处理的。

我在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的操作时,它会正确返回。

2 个答案:

答案 0 :(得分:1)

您可以通过以下方式include activity内的availability

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

答案 1 :(得分:1)

有很多方法可以做到这一点,但为了简单起见,我把这些事情放在了一个问题上。例如,在app / models / concerns

中的AvailabilitySearch

在可用性中,您包含它

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,以便从网址中删除所有空白的输入,因此它是干净的,如果它是共享的则是有意义的。

在coffeescript中,如果搜索表单的ID为&#39; search_form&#39;

$(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