Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Class that handles the PostgreSQL full text search for railscasts.com
class EpisodeSearch
attr_reader :ability, :options
delegate :sanitize, to: Episode
def initialize(ability, options = {})
@ability = ability
@options = options.dup
end
def tag
@tag ||= Tag.find_by_id(options[:tag_id]) if options[:tag_id].present?
end
def episodes(paginate = true)
episodes = (tag ? tag.episodes : Episode).accessible_by(ability).where(type_conditions)
episodes = episodes.paginate(page: page, per_page: per_page) if paginate
if options[:search]
episodes = episodes.where(search_conditions(options[:search])).order(order_clause)
else
episodes = episodes.recent
end
episodes
end
def similar_episodes(episode)
episodes(false).limit(5).where(search_conditions(episode.name, "OR")).where("episodes.id != ?", episode.id)
end
def type_conditions
case options[:type]
when "free" then {pro: false, revised: false}
when "pro" then {pro: true, revised: false}
when "revised" then {revised: true}
else {}
end
end
def search_conditions(query, join = "AND")
query.split(/\s+/).map do |word|
'(' + word_search_conditions(word).join(' OR ') + ')'
end.join(" #{join} ")
end
def word_search_conditions(word)
%w[name description notes].map do |col|
"to_tsvector('english', episodes.#{col}) @@ plainto_tsquery(#{sanitize(word)})"
end + ["episodes.position::varchar = #{sanitize(word)}"]
end
def order_clause
(search_order_clauses + extra_order_clauses).join(" + ") + " desc"
end
def search_order_clauses
{
name: 5,
description: 3,
notes: 1
}.map do |col, weight|
"(ts_rank(to_tsvector('english', episodes.#{col}), " +
"plainto_tsquery(#{sanitize(options[:search])})) * #{weight})"
end
end
def extra_order_clauses
[
"((date(episodes.published_at) - date '2007-01-01') * 0.0003)",
"(episodes.comments_count * 0.001)",
"(CASE episodes.revised WHEN TRUE THEN 0.02 ELSE 0 END)",
]
end
def per_page
if options[:per_page]
options[:per_page].to_i
else
case options[:view]
when "list" then 40
when "grid" then 24
else 10
end
end
end
def page
options[:page].to_i > 0 ? options[:page].to_i : 1
end
def applied_filters
filters = []
filters << [options[:search], options.merge(search: nil, page: nil)] if options[:search].present?
filters << ["#{options[:type].titleize} Episodes", options.merge(type: nil, page: nil)] if options[:type].present?
filters << [tag.display_name, options.merge(tag_id: nil, page: nil)] if tag
filters
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.