redis-autosuggest 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +7 -22
- data/lib/redis-autosuggest.rb +2 -2
- data/lib/redis/autosuggest.rb +76 -30
- data/lib/redis/autosuggest/config.rb +18 -9
- data/lib/redis/autosuggest/rails/railtie.rb +10 -0
- data/lib/redis/autosuggest/rails/rake_tasks.rb +9 -0
- data/lib/redis/autosuggest/rails/sources.rb +100 -0
- data/lib/redis/autosuggest/version.rb +1 -1
- data/redis-autosuggest.gemspec +2 -2
- data/test/autosuggest_test.rb +12 -4
- data/test/file_test.rb +0 -1
- metadata +9 -8
- data/lib/redis/autosuggest/init.rb +0 -17
- data/lib/redis/autosuggest/rails.rb +0 -49
data/README.md
CHANGED
@@ -5,16 +5,6 @@ Provides autocompletions through Redis, with the ability to rank
|
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
|
8
|
-
Add this line to your application's Gemfile:
|
9
|
-
|
10
|
-
gem 'redis-autosuggest'
|
11
|
-
|
12
|
-
And then execute:
|
13
|
-
|
14
|
-
$ bundle
|
15
|
-
|
16
|
-
Or install it yourself as:
|
17
|
-
|
18
8
|
$ gem install redis-autosuggest
|
19
9
|
|
20
10
|
## Usage
|
@@ -42,9 +32,9 @@ Autocompletions will be ordered their score value (descending).
|
|
42
32
|
Some other usage examples:
|
43
33
|
```ruby
|
44
34
|
# Add items with initial scores
|
45
|
-
Redis::Autosuggest.
|
35
|
+
Redis::Autosuggest.add_with_score("North By Northwest", 9, Northern Exposure, 3)
|
46
36
|
# Increment an item's score
|
47
|
-
Redis::Autosuggest.
|
37
|
+
Redis::Autosuggest.increment("North By Northwest", 1)
|
48
38
|
```
|
49
39
|
|
50
40
|
## Rails support
|
@@ -61,19 +51,14 @@ end
|
|
61
51
|
|
62
52
|
For first time usage, seed the Redis db with the autosuggest sources:
|
63
53
|
```ruby
|
64
|
-
|
54
|
+
rake autosuggest:init
|
65
55
|
```
|
66
56
|
|
67
57
|
You can optionally specify a numeric field to be used as the initial score for an item
|
68
|
-
when it is added:
|
58
|
+
when it is added and a limit of how many items maximum to keep:
|
69
59
|
```ruby
|
70
|
-
autosuggest
|
60
|
+
autosuggest :movie_title, :rank_by => imdb_rating, limit => 10000
|
71
61
|
```
|
72
62
|
|
73
|
-
##
|
74
|
-
|
75
|
-
1. Fork it
|
76
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
77
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
78
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
79
|
-
5. Create new Pull Request
|
63
|
+
## Front-end portion
|
64
|
+
Jquery plugin for dropdown autocompletions for a from can be found [here](https://github.com/aphan/jquery-rtsuggest)
|
data/lib/redis-autosuggest.rb
CHANGED
@@ -3,9 +3,9 @@ require 'redis-namespace'
|
|
3
3
|
require 'redis/autosuggest'
|
4
4
|
require 'redis/autosuggest/config'
|
5
5
|
require 'redis/autosuggest/file'
|
6
|
-
require 'redis/autosuggest/init'
|
7
6
|
require 'redis/autosuggest/version'
|
8
7
|
|
9
8
|
if defined?(Rails)
|
10
|
-
require 'redis/autosuggest/rails'
|
9
|
+
require 'redis/autosuggest/rails/sources'
|
10
|
+
require 'redis/autosuggest/rails/railtie'
|
11
11
|
end
|
data/lib/redis/autosuggest.rb
CHANGED
@@ -4,48 +4,54 @@ class Redis
|
|
4
4
|
class << self
|
5
5
|
|
6
6
|
# Add item(s) to the pool of items to autosuggest from. Each item's initial
|
7
|
-
# rank is 0
|
7
|
+
# rank is 0. Returns true if all items added were new, false otherwise.
|
8
8
|
def add(*items)
|
9
|
-
|
10
|
-
items.each do |
|
11
|
-
|
12
|
-
add_item(
|
9
|
+
all_new_items = true
|
10
|
+
items.each do |item|
|
11
|
+
item = item.downcase
|
12
|
+
item_exists?(item) ? all_new_items = false : add_item(item)
|
13
13
|
end
|
14
|
+
all_new_items
|
14
15
|
end
|
15
16
|
|
16
|
-
# Add item(s) along with their scores.
|
17
|
+
# Add item(s) along with their initial scores.
|
18
|
+
# Returns true if all items added were new, false otherwise.
|
17
19
|
# add_with_score("item1", 4, "item2", 1, "item3", 0)
|
18
20
|
def add_with_score(*fields)
|
19
|
-
|
21
|
+
all_new_items = true
|
20
22
|
fields.each_slice(2) do |f|
|
21
|
-
|
22
|
-
|
23
|
+
f[0] = normalize(f[0])
|
24
|
+
item_exists?(f[0]) ? all_new_items = false : add_item(*f)
|
23
25
|
end
|
26
|
+
all_new_items
|
24
27
|
end
|
25
28
|
|
26
|
-
# Remove an item from the pool of items to autosuggest from
|
29
|
+
# Remove an item from the pool of items to autosuggest from.
|
30
|
+
# Returns true if an item was indeed removed, false otherwise.
|
27
31
|
def remove(item)
|
28
32
|
item = item.downcase
|
29
33
|
id = get_id(item)
|
30
|
-
return if id.nil?
|
34
|
+
return false if id.nil?
|
31
35
|
@db.hdel(@items, id)
|
36
|
+
@db.hdel(@itemids, item)
|
32
37
|
remove_substrings(item, id)
|
33
38
|
@redis.zrem(@leaderboard, id) if @use_leaderboard
|
39
|
+
return true
|
34
40
|
end
|
35
41
|
|
36
|
-
# Increment the score (by 1 by default) of an item.
|
37
|
-
# to decrement the score
|
38
|
-
def increment(item,
|
39
|
-
item = item
|
42
|
+
# Increment the score (by 1 by default) of an item.
|
43
|
+
# Pass in a negative value to decrement the score.
|
44
|
+
def increment(item, incr=1)
|
45
|
+
item = normalize(item)
|
40
46
|
id = get_id(item)
|
41
|
-
each_substring(item) { |sub| @substrings.zincrby(sub,
|
42
|
-
@db.zincrby(@leaderboard,
|
47
|
+
each_substring(item) { |sub| @substrings.zincrby(sub, incr, id) }
|
48
|
+
@db.zincrby(@leaderboard, incr, id) if @use_leaderboard
|
43
49
|
end
|
44
50
|
|
45
51
|
# Suggest items from the database that most closely match the queried string.
|
46
|
-
# Returns an array of suggestion items (an empty array if nothing found)
|
52
|
+
# Returns an array of suggestion items (an empty array if nothing found).
|
47
53
|
def suggest(str, results=@max_results)
|
48
|
-
suggestion_ids = @substrings.zrevrange(str
|
54
|
+
suggestion_ids = @substrings.zrevrange(normalize(str), 0, results - 1)
|
49
55
|
suggestion_ids.empty? ? [] : @db.hmget(@items, suggestion_ids)
|
50
56
|
end
|
51
57
|
|
@@ -57,15 +63,32 @@ class Redis
|
|
57
63
|
|
58
64
|
# Get the score of an item
|
59
65
|
def get_score(item)
|
60
|
-
|
66
|
+
item = normalize(item)
|
67
|
+
@substrings.zscore(item, get_id(item))
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns whether or not an item is already stored in the db
|
71
|
+
def item_exists?(item)
|
72
|
+
return !get_id(normalize(item)).nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
# Get the id associated with an item in the db
|
76
|
+
def get_id(item)
|
77
|
+
return @db.hmget(@itemids, normalize(item)).first
|
61
78
|
end
|
62
79
|
|
63
80
|
private
|
81
|
+
|
82
|
+
def normalize(item)
|
83
|
+
return item.downcase.strip
|
84
|
+
end
|
85
|
+
|
64
86
|
def add_item(item, score=0)
|
65
|
-
id =
|
66
|
-
|
87
|
+
id = @db.hlen(@items)
|
88
|
+
@db.hset(@items, id, item)
|
89
|
+
@db.hset(@itemids, item, id)
|
67
90
|
add_substrings(item, score, id)
|
68
|
-
|
91
|
+
@db.zadd(@leaderboard, score, id) if @use_leaderboard
|
69
92
|
end
|
70
93
|
|
71
94
|
# Yield each substring of a complete string
|
@@ -75,19 +98,42 @@ class Redis
|
|
75
98
|
|
76
99
|
# Add all substrings of a string to redis
|
77
100
|
def add_substrings(str, score, id)
|
78
|
-
each_substring(str)
|
101
|
+
each_substring(str) do |sub|
|
102
|
+
if @max_per_substring == Float::INFINITY
|
103
|
+
add_substring(sub, score, id)
|
104
|
+
else
|
105
|
+
add_substring_limit(sub, score, id)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Add the id of an item to a substring
|
111
|
+
def add_substring(sub, score, id)
|
112
|
+
@substrings.zadd(sub, score, id)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Add the id of an item to a substring only when the number of items that
|
116
|
+
# substring stores is less then the config value of "max_per_substring".
|
117
|
+
# If the substring set is already full, check to see if the item with the
|
118
|
+
# lowest score in the substring set has a lower score than the item being added.
|
119
|
+
# If yes, remove that item and add this item to the substring set.
|
120
|
+
def add_substring_limit(sub, score, id)
|
121
|
+
count = @substrings.zcount(sub, "-inf", "inf")
|
122
|
+
if count < @max_per_substring
|
123
|
+
add_substring(sub, score, id)
|
124
|
+
else
|
125
|
+
lowest_item = @substrings.zrevrange(sub, -1, -1, { withscores: true }).last
|
126
|
+
if score > lowest_item[1]
|
127
|
+
@substrings.zrem(sub, lowest_item[0])
|
128
|
+
add_substring(sub, score, id)
|
129
|
+
end
|
130
|
+
end
|
79
131
|
end
|
80
132
|
|
81
133
|
# Remove all substrings of a string from the db
|
82
134
|
def remove_substrings(str, id)
|
83
135
|
each_substring(str) { |sub| @substrings.zrem(sub, id) }
|
84
136
|
end
|
85
|
-
|
86
|
-
# Get the id associated with an item in the db
|
87
|
-
def get_id(item)
|
88
|
-
kv_pair = @db.hgetall(@items).find { |_, v| v == item}
|
89
|
-
kv_pair.first unless kv_pair.nil?
|
90
|
-
end
|
91
137
|
end
|
92
138
|
end
|
93
139
|
end
|
@@ -3,46 +3,55 @@ class Redis
|
|
3
3
|
|
4
4
|
# Default Redis server at localhost:6379
|
5
5
|
@redis = Redis.new
|
6
|
+
|
7
|
+
# Main Redis namespace for this module
|
8
|
+
@namespace = "suggest"
|
6
9
|
|
7
|
-
@db = Redis::Namespace.new(
|
10
|
+
@db = Redis::Namespace.new(@namespace, :redis => @redis)
|
8
11
|
|
9
12
|
# Key for a Redis hash mapping ids to items we want to use for autosuggest responses
|
10
13
|
@items = "items"
|
11
14
|
|
15
|
+
# Key to a Redis hash mapping items to their respective ids
|
16
|
+
@itemids = "itemids"
|
17
|
+
|
12
18
|
# If we want to autosuggest for partial matchings of the word: 'ruby', we would
|
13
19
|
# have four sorted sets: 'autosuggest:substring:r', 'autosuggest:substring:ru',
|
14
20
|
# 'autosuggest:substring:rub', and 'autosuggest:substring:ruby'.
|
15
21
|
# Each sorted set would the id to the word 'ruby'
|
16
|
-
@substrings = Redis::Namespace.new("
|
22
|
+
@substrings = Redis::Namespace.new("#{@namespace}:sub", :redis => @redis)
|
17
23
|
|
18
24
|
# max number of ids to store per substring.
|
19
25
|
@max_per_substring = Float::INFINITY
|
20
26
|
|
21
27
|
# max number of results to return for an autosuggest query
|
22
|
-
@max_results = 5
|
28
|
+
@max_results = 5
|
23
29
|
|
24
30
|
# Key to a sorted set holding all id of items in the autosuggest database sorted
|
25
31
|
# by their score
|
26
32
|
@leaderboard = "lead"
|
27
33
|
|
28
|
-
# Leaderboard
|
34
|
+
# Leaderboard on by default
|
29
35
|
@use_leaderboard = false
|
30
36
|
|
31
37
|
# Sources to be used for Autocomplete in rails.
|
32
38
|
# Example: { Movie => :movie_title }
|
33
39
|
@rails_sources = {}
|
34
40
|
|
41
|
+
# Stores the number of items the db has for each rails source
|
42
|
+
@rails_source_sizes = Redis::Namespace.new("#{@namespace}:size", :redis => @redis)
|
43
|
+
|
35
44
|
class << self
|
36
45
|
attr_reader :redis
|
37
|
-
attr_accessor :db, :items, :substrings, :max_per_substring, :max_results,
|
38
|
-
:leaderboard, :use_leaderboard, :rails_sources
|
46
|
+
attr_accessor :namespace, :db, :items, :substrings, :max_per_substring, :max_results,
|
47
|
+
:leaderboard, :use_leaderboard, :rails_sources, :rails_source_sizes
|
39
48
|
|
40
49
|
def redis=(redis)
|
41
50
|
@redis = redis
|
42
|
-
@db = Redis::Namespace.new(
|
43
|
-
@substrings = Redis::Namespace.new("
|
51
|
+
@db = Redis::Namespace.new(@namespace, :redis => redis)
|
52
|
+
@substrings = Redis::Namespace.new("#{@namespace}:sub", :redis => redis)
|
53
|
+
@rails_source_sizes = Redis::Namespace.new("#{@namespace}:size", :redis => redis)
|
44
54
|
end
|
45
55
|
end
|
46
56
|
end
|
47
57
|
end
|
48
|
-
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class Redis
|
2
|
+
module Autosuggest
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
def autosuggest(column, options={})
|
7
|
+
hash = Redis::Autosuggest.rails_sources[self]
|
8
|
+
if hash.nil?
|
9
|
+
Redis::Autosuggest.rails_sources[self] = { column => options }
|
10
|
+
else
|
11
|
+
hash[column] = options
|
12
|
+
end
|
13
|
+
|
14
|
+
# Hook onto rails callbacks to update autosuggest db if a source is modified
|
15
|
+
class_eval <<-HERE
|
16
|
+
after_create :add_to_autosuggest
|
17
|
+
def add_to_autosuggest
|
18
|
+
Redis::Autosuggest::SuggestRails.add_to_autosuggest(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
after_update :check_if_changed
|
22
|
+
def check_if_changed
|
23
|
+
Redis::Autosuggest::SuggestRails.check_if_changed(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
before_destroy :remove_from_autosuggest
|
27
|
+
def remove_from_autosuggest
|
28
|
+
Redis::Autosuggest::SuggestRails.remove_from_autosuggest(self)
|
29
|
+
end
|
30
|
+
HERE
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module SuggestRails
|
35
|
+
class << self
|
36
|
+
|
37
|
+
def init_rails_sources
|
38
|
+
Rails.application.eager_load!
|
39
|
+
Redis::Autosuggest.db.flushdb
|
40
|
+
Redis::Autosuggest.rails_sources.each do |model, attrs|
|
41
|
+
attrs.each do |column, options|
|
42
|
+
order = options[:init_order] || ""
|
43
|
+
model.order(order).find_each do |record|
|
44
|
+
puts "Adding #{record.send(column)}"
|
45
|
+
size = self.add_source_attr(record, column, options)
|
46
|
+
break if size >= options[:limit]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_to_autosuggest(record)
|
53
|
+
Redis::Autosuggest.rails_sources[record.class].each do |column, options|
|
54
|
+
self.add_source_attr(record, column, options)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_source_attr(record, column, options)
|
59
|
+
item = record.send(column)
|
60
|
+
size = self.get_size(record.class, column).to_i
|
61
|
+
if size < options[:limit]
|
62
|
+
score = record.send(options[:rank_by]) unless options[:rank_by].nil?
|
63
|
+
score ||= 0
|
64
|
+
is_new_item = Redis::Autosuggest.add_with_score(item, score)
|
65
|
+
size = self.incr_size(record.class, column) if is_new_item
|
66
|
+
end
|
67
|
+
return size
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_if_changed(record)
|
71
|
+
Redis::Autosuggest.rails_sources[record.class].each_key do |column|
|
72
|
+
next unless record.send("#{column}_changed?")
|
73
|
+
old_item = record.send("#{column}_was")
|
74
|
+
score = Redis::Autosuggest.get_score(old_item)
|
75
|
+
Redis::Autosuggest.remove(old_item)
|
76
|
+
Redis::Autosuggest.add_with_score(record.send(column), score)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def remove_from_autosuggest(record)
|
81
|
+
Redis::Autosuggest.rails_sources[record.class].each_key do |column|
|
82
|
+
item = record.send(column)
|
83
|
+
item_was_in_db = Redis::Autosuggest.remove(item)
|
84
|
+
self.incr_size(record.class, column, -1) if item_was_in_db
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get the size (how many items) of a model/attribute pair
|
89
|
+
def get_size(model, attr)
|
90
|
+
Redis::Autosuggest.rails_source_sizes.get("#{model}:#{attr}")
|
91
|
+
end
|
92
|
+
|
93
|
+
# Increment the key storing the size of a model/attribute pair
|
94
|
+
def incr_size(model, attr, incr=1)
|
95
|
+
return Redis::Autosuggest.rails_source_sizes.incrby("#{model}:#{attr}", incr)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/redis-autosuggest.gemspec
CHANGED
@@ -18,8 +18,8 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
-
gem.add_dependency("redis", "~> 3.0.
|
21
|
+
gem.add_dependency("redis", "~> 3.0.2")
|
22
22
|
gem.add_dependency("redis-namespace", "~> 1.2.1")
|
23
23
|
|
24
|
-
gem.add_development_dependency("minitest", "~> 3.
|
24
|
+
gem.add_development_dependency("minitest", "~> 4.3.3")
|
25
25
|
end
|
data/test/autosuggest_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class TestAutosuggest < MiniTest::Unit::TestCase
|
4
|
-
|
4
|
+
|
5
5
|
def self.unused_db
|
6
6
|
@unused_db ||= Redis.new(:db => TestHelper.db_picker)
|
7
7
|
end
|
@@ -44,7 +44,7 @@ class TestAutosuggest < MiniTest::Unit::TestCase
|
|
44
44
|
assert @subs.keys.size == 10
|
45
45
|
end
|
46
46
|
|
47
|
-
|
47
|
+
def test_adding_multiple_items_with_scores
|
48
48
|
Redis::Autosuggest.add_with_score("one", 1, "two", 2, "three", 3)
|
49
49
|
assert @db.hgetall(Redis::Autosuggest.items).size == 3
|
50
50
|
assert @subs.keys.size == 10
|
@@ -101,8 +101,16 @@ class TestAutosuggest < MiniTest::Unit::TestCase
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def test_getting_an_items_score
|
104
|
-
|
105
|
-
|
104
|
+
Redis::Autosuggest.add_with_score(@str1, 3)
|
105
|
+
assert_equal 3, Redis::Autosuggest.get_score(@str1)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_adding_with_substring_limit
|
109
|
+
Redis::Autosuggest.max_per_substring = 1
|
110
|
+
Redis::Autosuggest.add_with_score(@str1, 1)
|
111
|
+
Redis::Autosuggest.add_with_score("Test", 5)
|
112
|
+
item_id = Redis::Autosuggest.get_id("Test")
|
113
|
+
assert_equal [item_id], @subs.zrevrange("test", 0, -1)
|
106
114
|
end
|
107
115
|
|
108
116
|
MiniTest::Unit.after_tests { self.unused_db.flushdb }
|
data/test/file_test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-autosuggest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 3.0.
|
21
|
+
version: 3.0.2
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 3.0.
|
29
|
+
version: 3.0.2
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: redis-namespace
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 3.
|
53
|
+
version: 4.3.3
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 3.
|
61
|
+
version: 4.3.3
|
62
62
|
description: ! "Provides autocompletions through Redis, with the ability to rank\n
|
63
63
|
\ results and integrate with Rails"
|
64
64
|
email:
|
@@ -76,8 +76,9 @@ files:
|
|
76
76
|
- lib/redis/autosuggest.rb
|
77
77
|
- lib/redis/autosuggest/config.rb
|
78
78
|
- lib/redis/autosuggest/file.rb
|
79
|
-
- lib/redis/autosuggest/
|
80
|
-
- lib/redis/autosuggest/rails.rb
|
79
|
+
- lib/redis/autosuggest/rails/railtie.rb
|
80
|
+
- lib/redis/autosuggest/rails/rake_tasks.rb
|
81
|
+
- lib/redis/autosuggest/rails/sources.rb
|
81
82
|
- lib/redis/autosuggest/version.rb
|
82
83
|
- redis-autosuggest.gemspec
|
83
84
|
- test/autosuggest_test.rb
|
@@ -1,49 +0,0 @@
|
|
1
|
-
class Redis
|
2
|
-
module Autosuggest
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
module ClassMethods
|
6
|
-
|
7
|
-
def autosuggest(column, options={})
|
8
|
-
hash = Redis::Autosuggest.rails_sources[self]
|
9
|
-
if hash.nil?
|
10
|
-
Redis::Autosuggest.rails_sources[self] = { column => options }
|
11
|
-
else
|
12
|
-
hash[column] = options
|
13
|
-
end
|
14
|
-
|
15
|
-
# hook onto rails callbacks to update autosuggest db if a source is modified
|
16
|
-
class_eval <<-HERE
|
17
|
-
after_create :add_to_autosuggest
|
18
|
-
def add_to_autosuggest
|
19
|
-
Redis::Autosuggest.rails_sources[self.class].each do |column, options|
|
20
|
-
score = self.send(options[:rank_by]) if !options[:rank_by].nil?
|
21
|
-
score ||= 0
|
22
|
-
Redis::Autosuggest.add_with_score(self.send(column), score)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
after_update :check_if_changed
|
27
|
-
def check_if_changed
|
28
|
-
Redis::Autosuggest.rails_sources[self.class].each_key do |column|
|
29
|
-
next if !self.send("#{column}_changed?")
|
30
|
-
old_item = self.send("#{column}_was")
|
31
|
-
score = Redis::Autosuggest.get_score(old_item)
|
32
|
-
Redis::Autosuggest.remove(old_item)
|
33
|
-
Redis::Autosuggest.add_with_score(self.send(column), score)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
before_destroy :remove_from_autosuggest
|
38
|
-
def remove_from_autosuggest
|
39
|
-
Redis::Autosuggest.rails_sources[self.class].each_key do |column|
|
40
|
-
Redis::Autosuggest.remove(self.send(column))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
HERE
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
|