Использование областей для поисковых запросов
Я работаю над улучшением моей функциональности поиска в моем приложении с помощью моделей.
Это то, что я использовал до сих пор:
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