diff --git a/app/models/debate.rb b/app/models/debate.rb index 11617319b..30c13f709 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -6,6 +6,7 @@ class Debate < ActiveRecord::Base include Measurable include Sanitizable include PgSearch + include SearchCache include Filterable apply_simple_captcha @@ -41,21 +42,28 @@ class Debate < ActiveRecord::Base visitable # Ahoy will automatically assign visit_id on create pg_search_scope :pg_search, { - against: { - title: 'A', - description: 'B' - }, - associated_against: { - tags: :name - }, + against: :ignored, # not used since the using: option has a tsvector_column using: { - tsearch: { dictionary: "spanish" }, + tsearch: { dictionary: "spanish", tsvector_column: 'tsv', prefix: true } }, ignoring: :accents, ranked_by: '(:tsearch)', order_within_rank: "debates.cached_votes_up DESC" } + def searchable_values + { title => 'A', + author.username => 'B', + tag_list.join(' ') => 'B', + geozone.try(:name) => 'B', + description => 'D' + } + end + + def self.search(terms) + self.pg_search(terms) + end + def description super.try :html_safe end @@ -121,15 +129,6 @@ class Debate < ActiveRecord::Base cached_votes_up) end - def self.search(terms) - return none unless terms.present? - - debate_ids = where("debates.title ILIKE ? OR debates.description ILIKE ?", - "%#{terms}%", "%#{terms}%").pluck(:id) - tag_ids = tagged_with(terms, wild: true, any: true).pluck(:id) - where(id: [debate_ids, tag_ids].flatten.compact) - end - def after_hide self.tags.each{ |t| t.decrement_custom_counter_for('Debate') } end diff --git a/db/migrate/20160204134022_add_tsvector_to_debates.rb b/db/migrate/20160204134022_add_tsvector_to_debates.rb new file mode 100644 index 000000000..1f15e4d6b --- /dev/null +++ b/db/migrate/20160204134022_add_tsvector_to_debates.rb @@ -0,0 +1,13 @@ +class AddTsvectorToDebates < ActiveRecord::Migration + + def up + add_column :debates, :tsv, :tsvector + add_index :debates, :tsv, using: "gin" + end + + def down + remove_index :debates, :tsv + remove_column :debates, :tsv + end + +end diff --git a/db/schema.rb b/db/schema.rb index ce259bc39..dafbdd4b0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160126090634) do +ActiveRecord::Schema.define(version: 20160204134022) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -120,6 +120,7 @@ ActiveRecord::Schema.define(version: 20160126090634) do t.integer "confidence_score", default: 0 t.string "external_link", limit: 100 t.integer "geozone_id" + t.tsvector "tsv" end add_index "debates", ["author_id", "hidden_at"], name: "index_debates_on_author_id_and_hidden_at", using: :btree @@ -134,6 +135,7 @@ ActiveRecord::Schema.define(version: 20160126090634) do add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree add_index "debates", ["hot_score"], name: "index_debates_on_hot_score", using: :btree add_index "debates", ["title"], name: "index_debates_on_title", using: :btree + add_index "debates", ["tsv"], name: "index_debates_on_tsv", using: :gin create_table "delayed_jobs", force: :cascade do |t| t.integer "priority", default: 0, null: false diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 477994c1f..5dea879a6 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -778,32 +778,32 @@ feature 'Debates' do end end - xscenario "Order by relevance by default", :js do + scenario "Order by relevance by default", :js do debate1 = create(:debate, title: "Show you got", cached_votes_up: 10) debate2 = create(:debate, title: "Show what you got", cached_votes_up: 1) debate3 = create(:debate, title: "Show you got", cached_votes_up: 100) visit debates_path - fill_in "search", with: "Show what you got" + fill_in "search", with: "Show you got" click_button "Search" expect(page).to have_selector("a.active", text: "relevance") within("#debates") do - expect(all(".debate")[0].text).to match "Show what you got" + expect(all(".debate")[0].text).to match "Show you got" expect(all(".debate")[1].text).to match "Show you got" - expect(all(".debate")[2].text).to match "Show you got" + expect(all(".debate")[2].text).to match "Show what you got" end end - xscenario "Reorder results maintaing search", :js do + scenario "Reorder results maintaing search", :js do debate1 = create(:debate, title: "Show you got", cached_votes_up: 10, created_at: 1.week.ago) debate2 = create(:debate, title: "Show what you got", cached_votes_up: 1, created_at: 1.month.ago) debate3 = create(:debate, title: "Show you got", cached_votes_up: 100, created_at: Time.now) debate4 = create(:debate, title: "Do not display", cached_votes_up: 1, created_at: 1.week.ago) visit debates_path - fill_in "search", with: "Show what you got" + fill_in "search", with: "Show you got" click_button "Search" click_link 'newest' expect(page).to have_selector("a.active", text: "newest") @@ -960,12 +960,12 @@ feature 'Debates' do debate5 = create(:debate, title: "Fifth debate has 5 votes", cached_votes_up: 5) debate6 = create(:debate, title: "Sixth debate has 6 votes", description: 'This is the sixth debate', cached_votes_up: 6) debate7 = create(:debate, title: "This has seven votes, and is not suggest", description: 'This is the seven', cached_votes_up: 7) - + visit new_debate_path - fill_in 'debate_title', with: 'debate' + fill_in 'debate_title', with: 'debate' check "debate_terms_of_service" - within('div#js-suggest') do + within('div#js-suggest') do expect(page).to have_content ("You are seeing 5 of 6 debates containing the term 'debate'") end end @@ -976,14 +976,14 @@ feature 'Debates' do debate1 = create(:debate, title: "First debate has 10 vote", cached_votes_up: 10) debate2 = create(:debate, title: "Second debate has 2 votes", cached_votes_up: 2) - + visit new_debate_path fill_in 'debate_title', with: 'proposal' - check "debate_terms_of_service" + check "debate_terms_of_service" within('div#js-suggest') do expect(page).to_not have_content ('You are seeing') end - end + end end end diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 5ce8c6d0e..04132224a 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -436,26 +436,26 @@ describe Debate do context "attributes" do - xit "searches by title" do + it "searches by title" do debate = create(:debate, title: 'save the world') results = Debate.search('save the world') expect(results).to eq([debate]) end - xit "searches by description" do + it "searches by description" do debate = create(:debate, description: 'in order to save the world one must think about...') results = Debate.search('one must think') expect(results).to eq([debate]) end - xit "searches by author name" do + it "searches by author name" do author = create(:user, username: 'Danny Trejo') debate = create(:debate, author: author) results = Debate.search('Danny') expect(results).to eq([debate]) end - xit "searches by geozone" do + it "searches by geozone" do geozone = create(:geozone, name: 'California') debate = create(:debate, geozone: geozone) results = Debate.search('California') @@ -466,7 +466,7 @@ describe Debate do context "stemming" do - xit "searches word stems" do + it "searches word stems" do debate = create(:debate, title: 'limpiar') results = Debate.search('limpiará') @@ -483,7 +483,7 @@ describe Debate do context "accents" do - xit "searches with accents" do + it "searches with accents" do debate = create(:debate, title: 'difusión') results = Debate.search('difusion') @@ -492,13 +492,16 @@ describe Debate do debate2 = create(:debate, title: 'estadisticas') results = Debate.search('estadísticas') expect(results).to eq([debate2]) + + debate3 = create(:debate, title: 'público') + results = Debate.search('publico') + expect(results).to eq([debate3]) end end context "case" do - - xit "searches case insensite" do + it "searches case insensite" do debate = create(:debate, title: 'SHOUT') results = Debate.search('shout') @@ -508,27 +511,23 @@ describe Debate do results = Debate.search("SCREAM") expect(results).to eq([debate2]) end - end - context "typos" do + context "tags" do + it "searches by tags" do + debate = create(:debate, tag_list: 'Latina') - xit "searches with typos" do - debate = create(:debate, title: 'difusión') + results = Debate.search('Latina') + expect(results.first).to eq(debate) - results = Debate.search('difuon') - expect(results).to eq([debate]) - - debate2 = create(:debate, title: 'desarrollo') - results = Debate.search('desarolo') - expect(results).to eq([debate2]) + results = Debate.search('Latin') + expect(results.first).to eq(debate) end - end context "order" do - xit "orders by weight" do + it "orders by weight" do debate_description = create(:debate, description: 'stop corruption') debate_title = create(:debate, title: 'stop corruption') @@ -538,7 +537,7 @@ describe Debate do expect(results.second).to eq(debate_description) end - xit "orders by weight and then votes" do + it "orders by weight and then votes" do title_some_votes = create(:debate, title: 'stop corruption', cached_votes_up: 5) title_least_voted = create(:debate, title: 'stop corruption', cached_votes_up: 2) title_most_voted = create(:debate, title: 'stop corruption', cached_votes_up: 10) @@ -547,28 +546,26 @@ describe Debate do results = Debate.search('stop corruption') expect(results.first).to eq(title_most_voted) - expect(results.second).to eq(description_most_voted) - expect(results.third).to eq(title_some_votes) - expect(results.fourth).to eq(title_least_voted) + expect(results.second).to eq(title_some_votes) + expect(results.third).to eq(title_least_voted) + expect(results.fourth).to eq(description_most_voted) end - xit "orders by weight and then votes and then created_at" do - newest = create(:debate, title: 'stop corruption', cached_votes_up: 5, created_at: Time.now) - oldest = create(:debate, title: 'stop corruption', cached_votes_up: 5, created_at: 1.month.ago) - old = create(:debate, title: 'stop corruption', cached_votes_up: 5, created_at: 1.week.ago) + it "gives much more weight to word matches than votes" do + exact_title_few_votes = create(:debate, title: 'stop corruption', cached_votes_up: 5) + similar_title_many_votes = create(:debate, title: 'stop some of the corruption', cached_votes_up: 500) results = Debate.search('stop corruption') - expect(results.first).to eq(newest) - expect(results.second).to eq(old) - expect(results.third).to eq(oldest) + expect(results.first).to eq(exact_title_few_votes) + expect(results.second).to eq(similar_title_many_votes) end end context "reorder" do - xit "should be able to reorder by hot_score after searching" do + it "should be able to reorder by hot_score after searching" do lowest_score = create(:debate, title: 'stop corruption', cached_votes_up: 1) highest_score = create(:debate, title: 'stop corruption', cached_votes_up: 2) average_score = create(:debate, title: 'stop corruption', cached_votes_up: 3) @@ -590,7 +587,7 @@ describe Debate do expect(results.third).to eq(lowest_score) end - xit "should be able to reorder by confidence_score after searching" do + it "should be able to reorder by confidence_score after searching" do lowest_score = create(:debate, title: 'stop corruption', cached_votes_up: 1) highest_score = create(:debate, title: 'stop corruption', cached_votes_up: 2) average_score = create(:debate, title: 'stop corruption', cached_votes_up: 3) @@ -612,7 +609,7 @@ describe Debate do expect(results.third).to eq(lowest_score) end - xit "should be able to reorder by created_at after searching" do + it "should be able to reorder by created_at after searching" do recent = create(:debate, title: 'stop corruption', cached_votes_up: 1, created_at: 1.week.ago) newest = create(:debate, title: 'stop corruption', cached_votes_up: 2, created_at: Time.now) oldest = create(:debate, title: 'stop corruption', cached_votes_up: 3, created_at: 1.month.ago) @@ -630,7 +627,7 @@ describe Debate do expect(results.third).to eq(oldest) end - xit "should be able to reorder by most commented after searching" do + it "should be able to reorder by most commented after searching" do least_commented = create(:debate, title: 'stop corruption', cached_votes_up: 1, comments_count: 1) most_commented = create(:debate, title: 'stop corruption', cached_votes_up: 2, comments_count: 100) some_comments = create(:debate, title: 'stop corruption', cached_votes_up: 3, comments_count: 10) @@ -650,41 +647,30 @@ describe Debate do end - context "tags" do - - xit "searches by tags" do - debate = create(:debate, tag_list: 'Latina') - - results = Debate.search('Latina') - expect(results.first).to eq(debate) - end - - end - context "no results" do - xit "no words match" do + it "no words match" do debate = create(:debate, title: 'save world') results = Debate.search('destroy planet') expect(results).to eq([]) end - xit "too many typos" do + it "too many typos" do debate = create(:debate, title: 'fantastic') results = Debate.search('frantac') expect(results).to eq([]) end - xit "too much stemming" do + it "too much stemming" do debate = create(:debate, title: 'reloj') results = Debate.search('superrelojimetro') expect(results).to eq([]) end - xit "empty" do + it "empty" do debate = create(:debate, title: 'great') results = Debate.search('')