Commit 13a3e7cbd5d9cf55a47381f71925bdeb3b96738c

Authored by AntonioTerceiro
1 parent b910579d

ActionItem25: providing a nice-looking and extensible search engine



git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@1002 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/controllers/public/search_controller.rb
1 class SearchController < ApplicationController 1 class SearchController < ApplicationController
  2 +
  3 + SEARCHES = []
  4 +
  5 + def self.search(&block)
  6 + SEARCHES << block
  7 + end
  8 +
  9 + protected
  10 +
  11 + #############################################
  12 + # XXX add yours searches here
  13 + #############################################
  14 +
  15 + search do |query|
  16 + Article.find_tagged_with(query)
  17 + end
  18 +
  19 + search do |query|
  20 + Article.find_by_contents(query)
  21 + end
  22 +
  23 + search do |query|
  24 + Profile.find_by_contents(query)
  25 + end
  26 +
  27 + # auxiliary method to search in all defined searches and collect the results
  28 + def search(query)
  29 + SEARCHES.inject([]) do |acc,finder|
  30 + acc += finder.call(query)
  31 + end.sort_by do |hit|
  32 + (hit.respond_to? :ferret_score) ? (1.0 - hit.ferret_score) : (-1.0)
  33 + end
  34 + end
  35 +
  36 + public
  37 +
2 def index 38 def index
3 @query = params[:query] || '' 39 @query = params[:query] || ''
4 - # TODO: uncomment find_by_contents when ferret start working  
5 - @results = Article.find_tagged_with(@query) + Article.find_all_by_title(@query) + Profile.find_all_by_name(@query) 40 + @results = search(@query)
6 end 41 end
  42 +
7 end 43 end
app/helpers/search_helper.rb
1 module SearchHelper 1 module SearchHelper
  2 + def partial_for_hit(klass)
  3 + name = klass.name.underscore
  4 + if File.exists?(File.join(RAILS_ROOT, 'app', 'views', 'search', "_#{name}.rhtml"))
  5 + name
  6 + else
  7 + partial_for_hit(klass.superclass)
  8 + end
  9 + end
2 end 10 end
app/models/article.rb
@@ -14,6 +14,8 @@ class Article &lt; ActiveRecord::Base @@ -14,6 +14,8 @@ class Article &lt; ActiveRecord::Base
14 14
15 acts_as_versioned 15 acts_as_versioned
16 16
  17 + acts_as_searchable :fields => [ :name, :abstract, :body ]
  18 +
17 # retrieves all articles belonging to the given +profile+ that are not 19 # retrieves all articles belonging to the given +profile+ that are not
18 # sub-articles of any other article. 20 # sub-articles of any other article.
19 def self.top_level_for(profile) 21 def self.top_level_for(profile)
app/models/profile.rb
@@ -15,7 +15,7 @@ class Profile &lt; ActiveRecord::Base @@ -15,7 +15,7 @@ class Profile &lt; ActiveRecord::Base
15 15
16 acts_as_design 16 acts_as_design
17 17
18 - acts_as_ferret :fields => [ :name ] 18 + acts_as_searchable :fields => [ :name, :identifier ]
19 19
20 # Valid identifiers must match this format. 20 # Valid identifiers must match this format.
21 IDENTIFIER_FORMAT = /^[a-z][a-z0-9_]*[a-z0-9]$/ 21 IDENTIFIER_FORMAT = /^[a-z][a-z0-9_]*[a-z0-9]$/
app/views/search/_article.rhtml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<div>
  2 + <strong>
  3 + <%= design_display_icon('cms') %>
  4 + <%= link_to_document(hit) %>
  5 + </strong>
  6 +</div>
  7 +<div>
  8 + <%= hit.abstract %>
  9 +</div>
  10 +
app/views/search/_profile.rhtml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<%# FIXME add photo if available %>
  2 +<%# FIXME add more information %>
  3 +
  4 +<div>
  5 + <strong>
  6 + <%= design_display_icon('person') %>
  7 + <%= link_to_homepage(hit.name, hit.identifier) %>
  8 + </strong>
  9 +</div>
app/views/search/index.rhtml
1 <h2> <%= _('Listing articles found') %> </h2> 1 <h2> <%= _('Listing articles found') %> </h2>
2 2
3 <h3> <%= _('Searching for ') + @query %></h3> 3 <h3> <%= _('Searching for ') + @query %></h3>
4 -<% @results.each do |a| %>  
5 - <h4> <%= link_to_document(a) if a.kind_of?(Article) %> </h4>  
6 - <h4> <%= link_to_homepage(a.name, a.identifier) if a.kind_of?(Profile) %> </h4>  
7 - 4 +<% @results.each do |hit| %>
  5 + <%= render :partial => partial_for_hit(hit.class), :locals => { :hit => hit } %>
  6 + <div class='search-relevance'>
  7 + <%= _('Relevance: %d%%') % (hit.respond_to?(:ferret_score) ? (hit.ferret_score * 100.0).round : 100) %>
  8 + </div>
  9 + <br style='clear: left'/>
8 <% end %> 10 <% end %>
config/ferret_server.yml
1 production: 1 production:
2 - host: ferret.yourdomain.com  
3 - port: 9010  
4 - pid_file: log/ferret.pid  
5 -development:  
6 host: localhost 2 host: localhost
7 port: 9010 3 port: 9010
8 pid_file: log/ferret.pid 4 pid_file: log/ferret.pid
9 -test:  
10 - host: localhost  
11 - port: 9009  
12 - pid_file: log/ferret.pid  
lib/acts_as_searchable.rb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +class << ActiveRecord::Base
  2 +
  3 + def acts_as_searchable(options = {}, ferret_options = {})
  4 + acts_as_ferret({ :remote => true }.merge(options), ferret_options)
  5 + end
  6 +
  7 +end
public/designs/icons/default/README
@@ -15,6 +15,7 @@ abiword_48.png dlg-neu apps/ @@ -15,6 +15,7 @@ abiword_48.png dlg-neu apps/
15 gtk-save.png Nuovo stock/ 15 gtk-save.png Nuovo stock/
16 gtk-go-up.png Nuovo stock/ 16 gtk-go-up.png Nuovo stock/
17 gtk-cancel.png Nuovo stock/ 17 gtk-cancel.png Nuovo stock/
  18 +user_icon.png Nuovo apps/
18 19
19 Licensing of GNOME themes 20 Licensing of GNOME themes
20 ========================= 21 =========================
public/designs/icons/default/style.css
@@ -7,3 +7,4 @@ @@ -7,3 +7,4 @@
7 .button.save { background-image: url(gtk-save.png); } 7 .button.save { background-image: url(gtk-save.png); }
8 .button.up { background-image: url(gtk-go-up.png); } 8 .button.up { background-image: url(gtk-go-up.png); }
9 .button.cancel { background-image: url(gtk-cancel.png); } 9 .button.cancel { background-image: url(gtk-cancel.png); }
  10 +.button.person { background-image: url(user_icon.png); }
public/designs/icons/default/user_icon.png 0 → 100644

851 Bytes

public/stylesheets/search.css 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +.search-relevance {
  2 + font-size: smaller;
  3 + font-style: italic;
  4 + color: gray;
  5 +}