使用搜索查询的范围
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
我正在努力通过使用模型改进我的应用程序中的搜索功能。
这是我到目前为止一直在使用的:
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