Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sitewide Search #71

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ gem "rest-client", '~> 1.6.3' # For University-Web

gem "twitter", :require => false
gem "whenever", :require => false
gem 'texticle', '~> 2.0', :require => 'texticle/rails'

gem 'newman', '~> 0.1.1'

Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ GEM
tilt (~> 1.1, != 1.3.0)
test_notifier (1.0.0)
notifier
texticle (2.0.3)
activerecord (~> 3.0)
therubyracer (0.9.9)
libv8 (~> 3.3.10)
thor (0.14.6)
Expand Down Expand Up @@ -245,6 +247,7 @@ DEPENDENCIES
sass-rails (~> 3.1.5.rc.2)
slugger (= 0.3.0)
test_notifier (~> 1.0.0)
texticle (~> 2.0)
therubyracer
twitter
uglifier (>= 1.0.3)
Expand Down
26 changes: 26 additions & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,32 @@ $(function(){
$(this).bigtext({maxfontsize: fontsize});
});

$('a.search-hover').click(function() {
$('div#search-nav').fadeToggle(function() {
$('.query').focus();
});
return false;
});

$('.close').click(function() {
$('div#search-nav').fadeOut();
return false;
});

//polyfill for placeholders in non-html5 browsers
$('[placeholder]').focus(function() {
var input = $(this);
if (input.val() == input.attr('placeholder')) {
input.val('');
input.removeClass('placeholder');
}
}).blur(function() {
var input = $(this);
if (input.val() == '' || input.val() == input.attr('placeholder')) {
input.addClass('placeholder');
input.val(input.attr('placeholder'));
}
}).blur();
})

$('a[data-submit]').live('click', function(e){
Expand Down
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.css.sass
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ $blueprint-grid-columns: 20
@import partials/fonts
@import partials/articles
@import partials/activities
@import partials/search
41 changes: 41 additions & 0 deletions app/assets/stylesheets/partials/_search.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.search-term
font-style: italic

#search-nav
display: none
z-index: 999
background-color: #3A3D50

-moz-border-radius: 5px
border-radius: 5px

-moz-box-shadow: 5px 5px 5px #888
-webkit-box-shadow: 5px 5px 5px #888
box-shadow: 5px 5px 5px #888

position: absolute
right: 150px
float: left

form
display: inline

.placeholder
color: #aaa

.query
margin: 5px
width: 150px

.hidden
margin: 0px
padding: 0px
width: 0px
visibility: hidden
display: none
float: none

.close
width: 20px
margin-right: 5px
padding: 5px
10 changes: 10 additions & 0 deletions app/controllers/search_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class SearchController < ApplicationController
respond_to :html

def index
@articles = Article.search_with_index(params[:query]).paginate(:page => params[:page])
@articles = @articles.public_only unless signed_in?
@articles = ArticleDecorator.decorate(@articles)
@results = SearchResults.new(params[:query], @articles)
end
end
13 changes: 13 additions & 0 deletions app/decorators/search_results.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class SearchResults
attr_reader :query
attr_reader :articles

def initialize(query, articles)
@query = query
@articles = articles
end

def articles_header
"#{@articles.count} search result#{ @articles.count == 1 ? "" : "s"} for: "
end
end
5 changes: 3 additions & 2 deletions app/models/article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ class Article < ActiveRecord::Base
opt.validates_length_of :title, :minimum => 3
end

scope :newest, order("sticky desc, created_at desc")
scope :public_only, where(:public => true)
scope :newest, order("sticky desc, created_at desc")
scope :public_only, where(:public => true)
scope :search_with_index, lambda { |query| search_by_title_or_body(query, query) }

def to_param
slug
Expand Down
2 changes: 1 addition & 1 deletion app/views/articles/_article.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@

.article_content= article.body

= render 'user_info', :article => article, :profile_size => "100"
= render 'articles/user_info', :article => article, :profile_size => "100"

= article.bottom(@articles, articles_path)
2 changes: 1 addition & 1 deletion app/views/articles/_header.html.haml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
- content_for(:section_name) { link_to "Updates", articles_path }
- content_for :section_controls do
= link_to "Post an update", new_article_path, :class => "clean-gray"
= link_to "Post an update", new_article_path, :class => "clean-gray"
2 changes: 1 addition & 1 deletion app/views/articles/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
.control-bar
= link_to 'Edit', edit_article_path(@article), :class => "clean-gray"
= link_to 'Destroy', @article, :confirm => 'Are you sure?',
:method => :delete, :class => "clean-gray warn"
:method => :delete, :class => "clean-gray warn"
3 changes: 3 additions & 0 deletions app/views/search/_header.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- content_for(:section_name) do
= @results.articles_header
.search-term= @results.query
7 changes: 7 additions & 0 deletions app/views/search/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- content_for(:title) { "Search results" }

= render :partial => "header"

#articles= render :partial => "articles/article", :collection => @results.articles

= will_paginate @results.articles
6 changes: 6 additions & 0 deletions app/views/shared/_navigation.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@
= link_to "Unicorns", page_path("unicorns")
- else
= link_to "About", about_path
= link_to "Search", "", :class => "search-hover"
%span#account
- if current_user
= link_to current_user.name, person_path(current_user.github)
= link_to "Sign out", logout_path
- else
= link_to "Sign in with Github", login_path
#search-nav
%form{:action => "/search", :method => "GET"}
%input.query.placeholder{:type => "text", :name => "query", :placeholder => "Search..."}
%input{:type => "submit", :id => "submit", :class => "hidden"}
%input.close{:type => "submit", :value => "X"}
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@

match '/about', to: 'pages#show', id: 'about', as: 'about'
match '/pages/:id', to: 'pages#show', as: 'page'

match '/search' => 'search#index'
end
14 changes: 14 additions & 0 deletions db/migrate/20120219213020_add_search_index_to_articles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class AddSearchIndexToArticles < ActiveRecord::Migration
def up
execute "
create index articles_title_idx on articles using gin(to_tsvector('english', title));
create index articles_body_idx on articles using gin(to_tsvector('english', body));"
end

def down
execute "
drop index articles_title_idx;
drop index articles_body_idx;
"
end
end
2 changes: 1 addition & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.

ActiveRecord::Schema.define(:version => 20120217002323) do
ActiveRecord::Schema.define(:version => 20120219213020) do

create_table "activities", :force => true do |t|
t.integer "author_id"
Expand Down
22 changes: 22 additions & 0 deletions test/integration/search_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'test_helper'

class SearchTest < ActionDispatch::IntegrationTest
def setup
@user = FactoryGirl.create(:user)
FactoryGirl.create(:article, title: "Article 1 - interesting", author: @user)
FactoryGirl.create(:article, title: "Article 2 - meh", author: @user)
end

test "articles can be searched" do
visit articles_path

within("#search-nav") do
fill_in "query", :with => "interesting"
click_button "submit"
end

assert_content("Article 1")
assert_no_content("Article 2")
end
end

2 changes: 1 addition & 1 deletion test/unit/article_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ def setup

assert_equal(1, Article.public_only.count)
end
end
end
26 changes: 26 additions & 0 deletions test/unit/search_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require 'test_helper'

class SearchTest < ActiveSupport::TestCase
def setup
@user = FactoryGirl.create(:user)
end

test "title can be searched" do
FactoryGirl.create(:article, title: "Article 1 - interesting", author: @user)
FactoryGirl.create(:article, title: "Article 2", author: @user)

titles = Article.search_with_index("interesting").map { |a| a.title }

assert_equal(["Article 1 - interesting"], titles)
end

test "body can be searched" do
FactoryGirl.create(:article, title: "Article 1", body: "interesting", author: @user)
FactoryGirl.create(:article, title: "Article 2", body: "boring", author: @user)

titles = Article.search_with_index("interesting").map { |a| a.title }

assert_equal(["Article 1"], titles)
end
end