Использование областей для поисковых запросов

Я работаю над улучшением моей функциональности поиска в моем приложении с помощью моделей.

Это то, что я использовал до сих пор:

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 ответа

Решение

Вы можете include activity в availability следующим образом:

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

Есть много способов сделать это, но для простоты я ставлю эти вещи в беспокойство. Например 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 на страницу поиска, чтобы избавиться от всех входных данных, которые являются пустыми от URL, поэтому он чистый и имеет смысл, если он используется совместно.

В coffeescript, учитывая, что форма поиска имеет идентификатор "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
Другие вопросы по тегам