Skip to content

Instantly share code, notes, and snippets.

@dwhite96
Last active December 17, 2017 22:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dwhite96/46bac35e07af4573676ef5cc161c0dde to your computer and use it in GitHub Desktop.
Save dwhite96/46bac35e07af4573676ef5cc161c0dde to your computer and use it in GitHub Desktop.
Add global search capabilities to aBox application using pg_search gem. User can search for artists, artwork, orders, etc. from any page.
<div id="nav" class="ui top stackable fixed menu">
<%= link_to "aBox", root_path, class: "link item" %>
<%= form_tag search_path, method: :get, class: "item", style: "width:400px" do %>
<div class="ui action input">
<%=
text_field_tag :search,
params[:search],
placeholder: "Search for artists, artwork, or orders"
%>
<%= button_tag "Search", type: "submit", name: nil, class: "ui teal basic button" %>
</div>
<% end %>
<div class="right menu">
<div id="cart" class="item">
<%= render partial: "order_items/cart" %>
</div>
<% if user_signed_in? %>
<%= link_to "Post artwork", new_artwork_path, class: "link item" %>
<%= link_to "My profile", profile_path, class: "link item" %>
<%= link_to "Edit profile", edit_user_registration_path, class: "link item" %>
<%= link_to "Logout", destroy_user_session_path, method: :delete, class: "link item" %>
<% else %>
<%= link_to "Sign up", new_user_registration_path, class: "link item" %>
<%= link_to "Login", new_user_session_path, class: "link item" %>
<% end %>
</div>
</div>
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
# GET /search
def search
@search_items = PgSearch.multisearch(params[:search])
end
end
require 'rails_helper'
RSpec.describe ApplicationController, type: :controller do
describe "GET #search" do
it "returns a success response" do
get :search
expect(response).to be_success
end
end
end
class ApplicationRecord < ActiveRecord::Base
include PgSearch
self.abstract_class = true
end
require 'rails_helper'
RSpec.describe ApplicationRecord, type: :model do
let(:user) { user = create(:user) }
let(:artwork) { artwork = create(:artwork) }
describe "global search index" do
it "returns any User object" do
search_result = PgSearch.multisearch(user.last_name)
expect(search_result.first.searchable_id).to eq user.id
end
it "returns any Artwork object" do
search_result = PgSearch.multisearch(artwork.title)
expect(search_result.first.searchable_id).to eq artwork.id
end
end
end
require "rails_helper"
RSpec.describe ApplicationController, type: :routing do
describe "routing" do
it "routes to #search" do
expect(get: "/search").to route_to("application#search")
end
end
end
# Base Artwork class
class Artwork < ApplicationRecord
multisearchable against: %i[title]
mount_uploader :photo, PhotoUploader
validates :title, presence: true
validates :price, presence: true
before_save :titleize_title, on: %i[create update]
belongs_to :gallery
has_many :order_items
has_many :orders, through: :order_items
private
def titleize_title
return unless errors.empty?
self.title = title.titleize
end
end
class Order < ApplicationRecord
multisearchable against: %i[id]
validates :status, presence: true
has_many :order_items, dependent: :destroy
has_many :artworks, through: :order_items
def quantity
self.order_items.count
end
end
Rails.application.routes.draw do
get 'search', to: 'application#search'
end
ActiveRecord::Schema.define(version: 20171210195126) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "pg_search_documents", force: :cascade do |t|
t.text "content"
t.string "searchable_type"
t.bigint "searchable_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["searchable_type", "searchable_id"], name: "index_pg_search_documents_on_searchable_type_and_searchable_id"
end
end
<p id="notice"><%= notice %></p>
<h1>Search results</h1>
<div class="ui divider"></div>
<div class="ui two column grid">
<div class="three wide column">
<div class="ui checkbox">
<input type="checkbox" name="example">
<label>Filter</label><br>
<label>Filter</label>
</div>
</div>
<div class="thirteen wide column">
<div class="ui stackable relaxed grid container">
<% @search_items.each do |search_item| %>
<div class="four wide column">
<%= link_to search_item.searchable do %>
<% if search_item.searchable.has_photo? %>
<%= image_tag(search_item.searchable.photo, class: "ui fluid image") %>
<% end %>
<%= search_item.content %>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
# Base User class
class User < ApplicationRecord
multisearchable against: %i[first_name last_name email]
alias_attribute :photo, :profile_photo
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
mount_uploader :profile_photo, PhotoUploader
validates :first_name, presence: true
validates :last_name, presence: true
validates :email, format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/ }
after_validation :format_name, on: %i[create update]
has_many :galleries, dependent: :destroy
has_many :artworks, through: :galleries
has_many :aboxes
accepts_nested_attributes_for :artworks, allow_destroy: true, reject_if: :all_blank
def format_name
return unless errors.empty?
self.first_name = first_name.downcase.titleize
self.last_name = last_name.downcase.titleize
end
def full_name
first_name << ' ' << last_name
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment