tkh_search 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +2 -0
- data/app/controllers/search_controller.rb +41 -0
- data/app/models/tkh_search.rb +5 -0
- data/app/models/tkh_search_instance.rb +12 -0
- data/app/models/tkh_search_query.rb +5 -0
- data/app/models/tkh_search_result.rb +5 -0
- data/app/models/tkh_search_term.rb +5 -0
- data/app/views/search/_search_form.html.erb +8 -0
- data/app/views/search/_search_form_for_navbar.html.erb +7 -0
- data/app/views/search/_search_results.html.erb +15 -0
- data/app/views/search/index.html.erb +9 -0
- data/app/views/search/index.js.erb +1 -0
- data/config/routes.rb +6 -0
- data/lib/generators/tkh_search/create_or_update_migrations/create_or_update_migrations_generator.rb +29 -0
- data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_instances.rb +21 -0
- data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_queries.rb +16 -0
- data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_results.rb +19 -0
- data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_terms.rb +16 -0
- data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_searches.rb +17 -0
- data/lib/generators/tkh_search/install_initializer/install_initializer_generator.rb +15 -0
- data/lib/generators/tkh_search/install_initializer/templates/tkh_search.rb +6 -0
- data/lib/tasks/tkh_search_tasks.rake +14 -0
- data/lib/tkh_search/tkh_searchable.rb +86 -0
- data/lib/tkh_search/version.rb +3 -0
- data/lib/tkh_search.rb +13 -0
- data/tkh_search.gemspec +26 -0
- metadata +132 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: b921e4f64a784fc89b26597164c8c2f1636b088d
|
|
4
|
+
data.tar.gz: 1eab786b215f5b7f45a3ade67d8480a82ca5340b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6aec8785495eba46ff3dfff3c6a698c50831223e3ea71537916a2a7a8d6bd2029fa929613762283fe9d1e1f57d46975d3de38cfc05519f75b828649721066d7a
|
|
7
|
+
data.tar.gz: 5eec46316e12505679dd82d5bde7975eeb3edc642a5e23138e43bc873f768e7deba11d9617e9fc89db9c078b9f18f2b59a62e72b3c4162763872e068aeb6ee39
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.1.2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Swami Atma
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# TkhSearch
|
|
2
|
+
|
|
3
|
+
This is a simple Rails gem search engine. It uses the local database for reverse indexing and to log search queries. Multi-model searches are supported.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
Add this line to your application's Gemfile:
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
gem 'tkh_search'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
And then execute:
|
|
15
|
+
|
|
16
|
+
$ bundle
|
|
17
|
+
|
|
18
|
+
Install initializer and migrations:
|
|
19
|
+
|
|
20
|
+
$ rake tkh_search:install
|
|
21
|
+
|
|
22
|
+
Run the migrations:
|
|
23
|
+
|
|
24
|
+
$ rake db:migrate
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Indexing the Models
|
|
28
|
+
|
|
29
|
+
In any model you want to index and search, copy/paste and customize the following code:
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
tkh_searchable
|
|
33
|
+
def self.tkh_search_indexable_fields
|
|
34
|
+
indexable_fields = {
|
|
35
|
+
title: 8,
|
|
36
|
+
description: 3,
|
|
37
|
+
body: 2
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Optionally the model may have a _'published?'_ attribute, virtual or not, to later refine admin and public searches.
|
|
43
|
+
|
|
44
|
+
To index a model's records, use the _'reverse_indexing'_ class method. Example:
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
ModelName.reverse_indexing
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Having configured all the models you wish to index in your search engine, you can index them all by first setting up the initializer.
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
TkhSearch::TkhSearchable.indexable_models = %w( Page Post Event WhateverYouWant )
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
and secondly, by pointing your browser to: /index_all_models
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## Searching your site
|
|
60
|
+
|
|
61
|
+
### Simple Setup - Searching one model in any given page
|
|
62
|
+
|
|
63
|
+
Render the basic search form:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
<%= render 'search/search_form', models_to_search: 'Page' %>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
By default the search is ajaxified. Just below the form, place a div to host the results:
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<div class="js-search-results"></div>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Searching multiple models
|
|
76
|
+
|
|
77
|
+
Just send the model names to the partial
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
<%= render 'search/search_form', models_to_search: 'Page Post Event' %>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Search form in Bootstrap navbar
|
|
84
|
+
|
|
85
|
+
There is a form partial to that effect.
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
<%= render 'search/search_form_for_navbar', models_to_search: 'Page' %>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Multiple search forms in a page
|
|
92
|
+
|
|
93
|
+
In this case you have to tell the gem in which div to render the results.
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
<%= render 'search/search_form_for_navbar', models_to_search: 'Page', results_css_class: 'blog-js-search-results' %>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
And of course, you need to place a div with the same class name under your form.
|
|
100
|
+
|
|
101
|
+
### Customize the submit button value
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
This can also be used for the sake of localization
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
<%= render 'search/search_form_for_navbar', models_to_search: 'Event', submit_label: 'find an awesome event' %>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
## Missing Features
|
|
112
|
+
|
|
113
|
+
This gem is brand new and will grow and mature.
|
|
114
|
+
|
|
115
|
+
Issues and pull requests welcome on Github.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
## Contributing
|
|
120
|
+
|
|
121
|
+
1. Fork it ( https://github.com/[my-github-username]/tkh_search/fork )
|
|
122
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
123
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
124
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
125
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
class SearchController < ApplicationController
|
|
2
|
+
|
|
3
|
+
def index
|
|
4
|
+
@query = params[:query].downcase
|
|
5
|
+
@models_to_search = params[:models_to_search].split
|
|
6
|
+
@results_css_class = params[:results_css_class] || 'js-search-results'
|
|
7
|
+
token = SecureRandom.base64
|
|
8
|
+
search_terms = []
|
|
9
|
+
@query.split.each do |query_word|
|
|
10
|
+
search_terms << TkhSearchTerm.find_by( word: query_word )
|
|
11
|
+
end
|
|
12
|
+
if search_terms.any?
|
|
13
|
+
search_terms.each do |search_term|
|
|
14
|
+
search_term.tkh_search_instances.each do |search_instance|
|
|
15
|
+
if @models_to_search.include? search_instance.model_name
|
|
16
|
+
search_result = TkhSearchResult.find_or_create_by(
|
|
17
|
+
token: token,
|
|
18
|
+
model_name: search_instance.model_name,
|
|
19
|
+
model_record_id: search_instance.model_record_id)
|
|
20
|
+
search_result.rating += search_instance.rating
|
|
21
|
+
search_result.save
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
@search_results = TkhSearchResult.where( token: token ).by_top_rating.limit(25)
|
|
27
|
+
respond_to do |format|
|
|
28
|
+
format.html {}
|
|
29
|
+
format.js {}
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def index_all_models
|
|
34
|
+
# to disable this, set initializer as an empty array
|
|
35
|
+
TkhSearch::TkhSearchable.indexable_models.each do |model|
|
|
36
|
+
Kernel.const_get(model).reverse_indexing
|
|
37
|
+
end
|
|
38
|
+
redirect_to root_path, notice: "All searchable models have been indexed."
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class TkhSearchInstance < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
belongs_to :tkh_search_term
|
|
4
|
+
|
|
5
|
+
scope :a_bit_old, -> { where('updated_at <= ?', ( Time.now - 2.minutes )) }
|
|
6
|
+
scope :by_top_rating, -> { order('rating desc') }
|
|
7
|
+
|
|
8
|
+
def unique_record_name
|
|
9
|
+
"#{model_name}-#{model_record_id}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%= form_tag search_path, class: 'search-form', remote: true do %>
|
|
2
|
+
<%= text_field_tag 'query', '', class: 'form-control' %>
|
|
3
|
+
<%= hidden_field_tag 'models_to_search', models_to_search %>
|
|
4
|
+
<%= hidden_field_tag 'results_css_class', ( results_css_class.present? ? results_css_class : nil ) %>
|
|
5
|
+
<%= button_tag type: 'submit', class: 'btn btn-default' do %>
|
|
6
|
+
<span class="glyphicon glyphicon-search"></span> <%= submit_label || 'search' %>
|
|
7
|
+
<% end %>
|
|
8
|
+
<% end %>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<%= form_tag search_path, class: 'navbar-form navbar-left navbar-search-form', remote: true do %>
|
|
2
|
+
<%= text_field_tag 'query', '', class: 'form-control' %>
|
|
3
|
+
<%= hidden_field_tag 'models_to_search', models_to_search %>
|
|
4
|
+
<%= button_tag type: 'submit', class: 'btn btn-default' do %>
|
|
5
|
+
<span class="glyphicon glyphicon-search"></span> search
|
|
6
|
+
<% end %>
|
|
7
|
+
<% end %>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<ul class="search-results">
|
|
2
|
+
<% if search_results.any? %>
|
|
3
|
+
<% search_results.each do |result| %>
|
|
4
|
+
<% record = (Kernel.const_get result.model_name).find(result.model_record_id) %>
|
|
5
|
+
<%= content_tag :li,
|
|
6
|
+
"<span class='sr-model-name'>#{result.model_name}</span> -
|
|
7
|
+
<span class='sr-model-name'>#{link_to record.name, record}</span> -
|
|
8
|
+
<span class='sr-rating'>#{result.rating}</span>
|
|
9
|
+
".html_safe
|
|
10
|
+
%>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% else %>
|
|
13
|
+
<li>There are no page results corresponding to this query.</li>
|
|
14
|
+
<% end %>
|
|
15
|
+
</ul>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<% content_for :meta_title, "searching for '#{@query}'" %>
|
|
2
|
+
<% content_for :meta_description, "Search results for the terms '#{@query}' in The Online Course for Western Yogis" %>
|
|
3
|
+
|
|
4
|
+
<h1>
|
|
5
|
+
Search Results for<br />
|
|
6
|
+
'<%= @query %>'
|
|
7
|
+
</h1>
|
|
8
|
+
|
|
9
|
+
<%= render 'search/search_results', search_results: @search_results %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$('.<%= @results_css_class %>').html("<%= escape_javascript(render( 'search/search_results', search_results: @search_results )) %>").hide().slideDown(500);
|
data/config/routes.rb
ADDED
data/lib/generators/tkh_search/create_or_update_migrations/create_or_update_migrations_generator.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'rails/generaTors/migration'
|
|
2
|
+
|
|
3
|
+
module TkhSearch
|
|
4
|
+
module Generators
|
|
5
|
+
class CreateOrUpdateMigrationsGenerator < ::Rails::Generators::Base
|
|
6
|
+
include Rails::Generators::Migration
|
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
8
|
+
desc "add the migrations and locale files"
|
|
9
|
+
def self.next_migration_number(path)
|
|
10
|
+
unless @prev_migration_nr
|
|
11
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
|
12
|
+
else
|
|
13
|
+
@prev_migration_nr += 1
|
|
14
|
+
end
|
|
15
|
+
@prev_migration_nr.to_s
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def copy_migrations
|
|
19
|
+
puts 'creating search migrations'
|
|
20
|
+
migration_template "create_tkh_search_terms.rb", "db/migrate/create_tkh_search_terms.rb"
|
|
21
|
+
migration_template "create_tkh_search_instances.rb", "db/migrate/create_tkh_search_instances.rb"
|
|
22
|
+
migration_template "create_tkh_search_queries.rb", "db/migrate/create_tkh_search_queries.rb"
|
|
23
|
+
migration_template "create_tkh_searches.rb", "db/migrate/create_tkh_searches.rb"
|
|
24
|
+
migration_template "create_tkh_search_results.rb", "db/migrate/create_tkh_search_results.rb"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_instances.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class CreateTkhSearchInstances < ActiveRecord::Migration
|
|
2
|
+
|
|
3
|
+
def self.up
|
|
4
|
+
create_table :tkh_search_instances do |t|
|
|
5
|
+
t.integer :tkh_search_term_id
|
|
6
|
+
t.string :model_name
|
|
7
|
+
t.integer :model_record_id
|
|
8
|
+
t.integer :rating
|
|
9
|
+
t.string :language
|
|
10
|
+
t.boolean :published, default: false
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
add_index :tkh_search_instances, :tkh_search_term_id
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.down
|
|
17
|
+
remove_index :tkh_search_instances, :tkh_search_term_id
|
|
18
|
+
drop_table :tkh_search_instances
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_queries.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CreateTkhSearchQueries < ActiveRecord::Migration
|
|
2
|
+
|
|
3
|
+
def self.up
|
|
4
|
+
create_table :tkh_search_queries do |t|
|
|
5
|
+
t.string :string
|
|
6
|
+
t.timestamps
|
|
7
|
+
end
|
|
8
|
+
add_index :tkh_search_queries, :string
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.down
|
|
12
|
+
remove_index :tkh_search_queries, :string
|
|
13
|
+
drop_table :tkh_search_queries
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_results.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class CreateTkhSearchResults < ActiveRecord::Migration
|
|
2
|
+
|
|
3
|
+
def self.up
|
|
4
|
+
create_table :tkh_search_results do |t|
|
|
5
|
+
t.string :token
|
|
6
|
+
t.string :model_name
|
|
7
|
+
t.integer :model_record_id
|
|
8
|
+
t.integer :rating, default: 0
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
add_index :tkh_search_results, :token
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.down
|
|
15
|
+
remove_index :tkh_search_results, :token
|
|
16
|
+
drop_table :tkh_search_results
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
data/lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_terms.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CreateTkhSearchTerms < ActiveRecord::Migration
|
|
2
|
+
|
|
3
|
+
def self.up
|
|
4
|
+
create_table :tkh_search_terms do |t|
|
|
5
|
+
t.string :word
|
|
6
|
+
t.timestamps
|
|
7
|
+
end
|
|
8
|
+
add_index :tkh_search_terms, :word
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.down
|
|
12
|
+
remove_index :tkh_search_terms, :word
|
|
13
|
+
drop_table :tkh_search_terms
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class CreateTkhSearches < ActiveRecord::Migration
|
|
2
|
+
|
|
3
|
+
def self.up
|
|
4
|
+
create_table :tkh_searches do |t|
|
|
5
|
+
t.integer :tkh_search_query_id
|
|
6
|
+
t.string :language
|
|
7
|
+
t.timestamps
|
|
8
|
+
end
|
|
9
|
+
add_index :tkh_searches, :tkh_search_query_id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.down
|
|
13
|
+
remove_index :tkh_searches, :tkh_search_query_id
|
|
14
|
+
drop_table :tkh_searches
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'rails/generaTors/migration'
|
|
2
|
+
|
|
3
|
+
module TkhSearch
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallInitializerGenerator < ::Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
7
|
+
|
|
8
|
+
desc "install initializer"
|
|
9
|
+
def set_up_search_initializer
|
|
10
|
+
copy_file "tkh_search.rb", "config/initializers/tkh_search.rb"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Populate the array with all the models you want to reverse index
|
|
2
|
+
# TkhSearch::TkhSearchable.indexable_models = %w( Page Post Event )
|
|
3
|
+
|
|
4
|
+
# Once you have indexed your site, you should reverse back to an empty array
|
|
5
|
+
# so that nobady can do any indexing.
|
|
6
|
+
TkhSearch::TkhSearchable.indexable_models = %w()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
namespace :tkh_search do
|
|
2
|
+
desc "Create migrations and locale files"
|
|
3
|
+
task :install do
|
|
4
|
+
system 'rails g tkh_search:install_initializer'
|
|
5
|
+
system 'rails g tkh_search:create_or_update_migrations'
|
|
6
|
+
# system 'rails g tkh_search:create_or_update_locales -f'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
desc "Update files. Skip existing migrations. Force overwrite locales"
|
|
10
|
+
task :update do
|
|
11
|
+
system 'rails g tkh_search:create_or_update_migrations -s'
|
|
12
|
+
# system 'rails g tkh_search:create_or_update_locales -f'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
module TkhSearch
|
|
2
|
+
module TkhSearchable
|
|
3
|
+
|
|
4
|
+
# to enable the initializer
|
|
5
|
+
mattr_accessor :indexable_models
|
|
6
|
+
|
|
7
|
+
# Class methods
|
|
8
|
+
|
|
9
|
+
def tkh_searchable
|
|
10
|
+
include TkhSearch::TkhSearchable::LocalInstanceMethods
|
|
11
|
+
after_save :index_record
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def reverse_indexing
|
|
15
|
+
# Any model must have a self.tkh_search_indexable_fields class method returning
|
|
16
|
+
# a hash of "field_name: :strength" pairs to be indexed
|
|
17
|
+
if defined? self.tkh_search_indexable_fields
|
|
18
|
+
# Index all records of the given model
|
|
19
|
+
self.all.each do |record|
|
|
20
|
+
index_individual_record(record)
|
|
21
|
+
end
|
|
22
|
+
else # no fields have been set in the model
|
|
23
|
+
"The model '#{self.name}' has no fields marked for indexing."
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def index_individual_record(record)
|
|
28
|
+
words = {}
|
|
29
|
+
# Loop through each indexable field
|
|
30
|
+
self.tkh_search_indexable_fields.each do |field_name, strength|
|
|
31
|
+
# Remove html tags, transform to lowercase and split words
|
|
32
|
+
# Splitting only with spaces because we want to preserve devanagari characters
|
|
33
|
+
Sanitize.fragment(record.send(field_name)).downcase.split.each do |word|
|
|
34
|
+
word = clean_up(word)
|
|
35
|
+
if words[word] # add strength to existing word rating
|
|
36
|
+
words[word] += strength
|
|
37
|
+
else # new word
|
|
38
|
+
words[word] = strength # create a new word pair
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
populate_index_tables( words, record )
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def clean_up(str)
|
|
48
|
+
str.strip.sub(/\,$/, '').sub(/\.$/, '').sub(/^\'/, '').sub(/\'$/, '').strip
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def populate_index_tables( words, record )
|
|
52
|
+
# populate tkh_search_terms and tkh_search_instances tables
|
|
53
|
+
words.each do |word,strength|
|
|
54
|
+
term = TkhSearchTerm.find_or_create_by( word: word )
|
|
55
|
+
instance = TkhSearchInstance.find_or_create_by(
|
|
56
|
+
model_name: self.name,
|
|
57
|
+
model_record_id: record.id,
|
|
58
|
+
tkh_search_term_id: term.id )
|
|
59
|
+
instance.rating = strength
|
|
60
|
+
instance.language = I18n.locale
|
|
61
|
+
defined?(record.published?) ? instance.published = record.published? : instance.published = false
|
|
62
|
+
instance.save!
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
module LocalInstanceMethods
|
|
67
|
+
def index_record
|
|
68
|
+
# get record's model name, constantize it, and call the indexing class method
|
|
69
|
+
(Kernel.const_get self.class.name).index_individual_record(self)
|
|
70
|
+
remove_obsolete_instances
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def remove_obsolete_instances
|
|
76
|
+
# after an individual record save and the record has been reindexed
|
|
77
|
+
# we need to remove indexed instances for words which have been deleted
|
|
78
|
+
obsolete_instances = TkhSearchInstance.where( 'model_name = ? and model_record_id = ?', self.class.name, self.id ).a_bit_old
|
|
79
|
+
obsolete_instances.each do |instance|
|
|
80
|
+
instance.destroy!
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
data/lib/tkh_search.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "tkh_search/version"
|
|
2
|
+
require 'active_record'
|
|
3
|
+
require 'sanitize'
|
|
4
|
+
|
|
5
|
+
require 'tkh_search/tkh_searchable'
|
|
6
|
+
|
|
7
|
+
module TkhSearch
|
|
8
|
+
class Engine < ::Rails::Engine
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# reopen ActiveRecord and include all the search methods
|
|
13
|
+
ActiveRecord::Base.extend TkhSearch::TkhSearchable
|
data/tkh_search.gemspec
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'tkh_search/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "tkh_search"
|
|
8
|
+
spec.version = TkhSearch::VERSION
|
|
9
|
+
spec.authors = ["Swami Atma"]
|
|
10
|
+
spec.email = ["swami@TenThousandHours.eu"]
|
|
11
|
+
spec.summary = %q{Lightweigh Rails search engine}
|
|
12
|
+
spec.description = %q{A Rails engine providing full text search via the DB. Not suitable for massive apps.}
|
|
13
|
+
spec.homepage = "https://github.com/allesklar/tkh_search"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_dependency 'activerecord'
|
|
22
|
+
spec.add_dependency 'sanitize'
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tkh_search
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Swami Atma
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-09-07 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activerecord
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: sanitize
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: bundler
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.7'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.7'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rake
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '10.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '10.0'
|
|
69
|
+
description: A Rails engine providing full text search via the DB. Not suitable for
|
|
70
|
+
massive apps.
|
|
71
|
+
email:
|
|
72
|
+
- swami@TenThousandHours.eu
|
|
73
|
+
executables: []
|
|
74
|
+
extensions: []
|
|
75
|
+
extra_rdoc_files: []
|
|
76
|
+
files:
|
|
77
|
+
- ".gitignore"
|
|
78
|
+
- ".ruby-version"
|
|
79
|
+
- Gemfile
|
|
80
|
+
- LICENSE.txt
|
|
81
|
+
- README.md
|
|
82
|
+
- Rakefile
|
|
83
|
+
- app/controllers/search_controller.rb
|
|
84
|
+
- app/models/tkh_search.rb
|
|
85
|
+
- app/models/tkh_search_instance.rb
|
|
86
|
+
- app/models/tkh_search_query.rb
|
|
87
|
+
- app/models/tkh_search_result.rb
|
|
88
|
+
- app/models/tkh_search_term.rb
|
|
89
|
+
- app/views/search/_search_form.html.erb
|
|
90
|
+
- app/views/search/_search_form_for_navbar.html.erb
|
|
91
|
+
- app/views/search/_search_results.html.erb
|
|
92
|
+
- app/views/search/index.html.erb
|
|
93
|
+
- app/views/search/index.js.erb
|
|
94
|
+
- config/routes.rb
|
|
95
|
+
- lib/generators/tkh_search/create_or_update_migrations/create_or_update_migrations_generator.rb
|
|
96
|
+
- lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_instances.rb
|
|
97
|
+
- lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_queries.rb
|
|
98
|
+
- lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_results.rb
|
|
99
|
+
- lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_search_terms.rb
|
|
100
|
+
- lib/generators/tkh_search/create_or_update_migrations/templates/create_tkh_searches.rb
|
|
101
|
+
- lib/generators/tkh_search/install_initializer/install_initializer_generator.rb
|
|
102
|
+
- lib/generators/tkh_search/install_initializer/templates/tkh_search.rb
|
|
103
|
+
- lib/tasks/tkh_search_tasks.rake
|
|
104
|
+
- lib/tkh_search.rb
|
|
105
|
+
- lib/tkh_search/tkh_searchable.rb
|
|
106
|
+
- lib/tkh_search/version.rb
|
|
107
|
+
- tkh_search.gemspec
|
|
108
|
+
homepage: https://github.com/allesklar/tkh_search
|
|
109
|
+
licenses:
|
|
110
|
+
- MIT
|
|
111
|
+
metadata: {}
|
|
112
|
+
post_install_message:
|
|
113
|
+
rdoc_options: []
|
|
114
|
+
require_paths:
|
|
115
|
+
- lib
|
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
|
+
requirements:
|
|
118
|
+
- - ">="
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: '0'
|
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - ">="
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: '0'
|
|
126
|
+
requirements: []
|
|
127
|
+
rubyforge_project:
|
|
128
|
+
rubygems_version: 2.2.2
|
|
129
|
+
signing_key:
|
|
130
|
+
specification_version: 4
|
|
131
|
+
summary: Lightweigh Rails search engine
|
|
132
|
+
test_files: []
|