From feec603b389332850401ef15896a0706f2830b5e Mon Sep 17 00:00:00 2001 From: Doug Cole Date: Tue, 27 Mar 2018 16:21:09 -0700 Subject: [PATCH 1/2] initial search functionality --- app/assets/javascripts/questions.js | 12 ++++++++++++ app/assets/javascripts/search.js | 2 ++ app/assets/stylesheets/search.scss | 3 +++ app/controllers/search_controller.rb | 7 +++++++ app/helpers/search_helper.rb | 2 ++ app/models/candidate.rb | 4 ++++ app/models/contest_search.rb | 20 ++++++++++++++++++++ app/views/layouts/application.html.erb | 2 ++ app/views/questions/new.html.erb | 14 +++++++++----- config/routes.rb | 1 + test/controllers/search_controller_test.rb | 7 +++++++ 11 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 app/assets/javascripts/search.js create mode 100644 app/assets/stylesheets/search.scss create mode 100644 app/controllers/search_controller.rb create mode 100644 app/helpers/search_helper.rb create mode 100644 app/models/contest_search.rb create mode 100644 test/controllers/search_controller_test.rb diff --git a/app/assets/javascripts/questions.js b/app/assets/javascripts/questions.js index dee720f..969b275 100644 --- a/app/assets/javascripts/questions.js +++ b/app/assets/javascripts/questions.js @@ -1,2 +1,14 @@ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. + + +$(document).ready(function() { + $('.select2').select2({ + ajax: { + url: '/search', + dataType: 'json' + }, + minimumInputLength: 3, + width: '200px' + }); +}); diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js new file mode 100644 index 0000000..dee720f --- /dev/null +++ b/app/assets/javascripts/search.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/search.scss b/app/assets/stylesheets/search.scss new file mode 100644 index 0000000..22fd394 --- /dev/null +++ b/app/assets/stylesheets/search.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the search controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb new file mode 100644 index 0000000..36751f6 --- /dev/null +++ b/app/controllers/search_controller.rb @@ -0,0 +1,7 @@ +class SearchController < ApplicationController + def index + result = ContestSearch.search(params[:q]).limit(4) + hash_results = result.map {|r| {id: r.id, text: r.name} } + render json: { "results": hash_results } + end +end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb new file mode 100644 index 0000000..b3ce20a --- /dev/null +++ b/app/helpers/search_helper.rb @@ -0,0 +1,2 @@ +module SearchHelper +end diff --git a/app/models/candidate.rb b/app/models/candidate.rb index 207c094..3a858a5 100644 --- a/app/models/candidate.rb +++ b/app/models/candidate.rb @@ -1,3 +1,7 @@ class Candidate < ApplicationRecord belongs_to :contest + + def name + primary_name + end end diff --git a/app/models/contest_search.rb b/app/models/contest_search.rb new file mode 100644 index 0000000..1f0a1e0 --- /dev/null +++ b/app/models/contest_search.rb @@ -0,0 +1,20 @@ +class ContestSearch + def self.search(query) + + columns = %w(primary_office_name secondary_office_name electoral_district_name) + tsvector = to_tsvector(columns) + results = Contest.where("to_tsvector(#{tsvector}) @@ to_tsquery('english', ?)", query + ":*") + + if results.empty? + columns = %w(primary_name primary_party secondary_name) + tsvector = to_tsvector(columns) + results = Candidate.where("to_tsvector(#{tsvector}) @@ to_tsquery('english', ?)", query + ":*") + end + + results + end + + def self.to_tsvector(columns) + columns.map {|c| "coalesce(#{c}, '')" }.join(" || ' ' || ") + end +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a4fa2a6..70090b3 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -11,6 +11,8 @@ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> + + diff --git a/app/views/questions/new.html.erb b/app/views/questions/new.html.erb index 135c568..d9cf9d7 100644 --- a/app/views/questions/new.html.erb +++ b/app/views/questions/new.html.erb @@ -1,5 +1,9 @@ -<%= form_for @question do |f|-%> - <%= f.select :contest_id, options_for_select(Contest.pluck(:name, :id)) -%> - <%= f.text_area :body -%> - <%= f.submit-%> -<% end -%> +
+
+ <%= form_for @question, html: {class: 'mw-100'} do |f|-%> +
<%= f.select :contest_id, '', {}, class: 'select2' -%>
+ <%= f.text_area :body -%> + <%= f.submit-%> + <% end -%> +
+
diff --git a/config/routes.rb b/config/routes.rb index eeebcb9..43d6afd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,4 +4,5 @@ resources :questions, :only => [:index, :new, :create] resources :votes, :only => :create + get 'search', to: 'search#index' end diff --git a/test/controllers/search_controller_test.rb b/test/controllers/search_controller_test.rb new file mode 100644 index 0000000..9341b7a --- /dev/null +++ b/test/controllers/search_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class SearchControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end From 259ac9dcdd4d838e05c5fc80ade8de8b57a005ba Mon Sep 17 00:00:00 2001 From: Doug Cole Date: Wed, 28 Mar 2018 13:29:57 -0700 Subject: [PATCH 2/2] add display name method, support multiword search --- app/controllers/search_controller.rb | 2 +- app/models/candidate.rb | 2 +- app/models/contest.rb | 4 ++++ app/models/contest_search.rb | 9 ++++++--- app/views/questions/_question.html.erb | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 36751f6..df3eedf 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,7 +1,7 @@ class SearchController < ApplicationController def index result = ContestSearch.search(params[:q]).limit(4) - hash_results = result.map {|r| {id: r.id, text: r.name} } + hash_results = result.map {|r| {id: r.id, text: r.display_name} } render json: { "results": hash_results } end end diff --git a/app/models/candidate.rb b/app/models/candidate.rb index 3a858a5..61651ad 100644 --- a/app/models/candidate.rb +++ b/app/models/candidate.rb @@ -1,7 +1,7 @@ class Candidate < ApplicationRecord belongs_to :contest - def name + def display_name primary_name end end diff --git a/app/models/contest.rb b/app/models/contest.rb index 375afc5..0a2a92f 100644 --- a/app/models/contest.rb +++ b/app/models/contest.rb @@ -1,2 +1,6 @@ class Contest < ApplicationRecord + + def display_name + "#{name} - #{electoral_district_name}" + end end diff --git a/app/models/contest_search.rb b/app/models/contest_search.rb index 1f0a1e0..5435476 100644 --- a/app/models/contest_search.rb +++ b/app/models/contest_search.rb @@ -1,14 +1,13 @@ class ContestSearch def self.search(query) - columns = %w(primary_office_name secondary_office_name electoral_district_name) tsvector = to_tsvector(columns) - results = Contest.where("to_tsvector(#{tsvector}) @@ to_tsquery('english', ?)", query + ":*") + results = Contest.where("to_tsvector(#{tsvector}) @@ to_tsquery('english', ?)", to_tsquery(query)) if results.empty? columns = %w(primary_name primary_party secondary_name) tsvector = to_tsvector(columns) - results = Candidate.where("to_tsvector(#{tsvector}) @@ to_tsquery('english', ?)", query + ":*") + results = Candidate.where("to_tsvector(#{tsvector}) @@ to_tsquery('english', ?)", to_tsquery(query)) end results @@ -17,4 +16,8 @@ def self.search(query) def self.to_tsvector(columns) columns.map {|c| "coalesce(#{c}, '')" }.join(" || ' ' || ") end + + def self.to_tsquery(query) + res = query.split(' ').map {|q| "#{q}:*" }.join(" & ") + end end diff --git a/app/views/questions/_question.html.erb b/app/views/questions/_question.html.erb index e35c9ed..e45e47e 100644 --- a/app/views/questions/_question.html.erb +++ b/app/views/questions/_question.html.erb @@ -9,7 +9,7 @@
votes
- Question for: <%= question.contest.name -%>
+ Question for: <%= question.contest.display_name -%>
<%= question.body -%>