searchtastic 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ *.rvmrc
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
6
+ coverage.data
7
+ coverage/*
8
+ .yardoc
9
+ tmp
10
+ vendor/bundle
11
+ *.swp
12
+ *.swo
13
+ *.DS_Store
14
+ .idea/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order rand
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake'
3
+ require 'rspec/core/rake_task'
4
+
5
+ namespace :spec do
6
+
7
+ RSpec::Core::RakeTask.new(:normal) do |t|
8
+ t.pattern ='spec/**/*_spec.rb'
9
+ t.rcov = false
10
+ end
11
+
12
+ end
13
+
14
+ desc "RSpec tests"
15
+ task "spec" => "spec:normal"
16
+
17
+ task "default" => "spec"
data/Readme.md ADDED
@@ -0,0 +1,67 @@
1
+ # Searchtastic
2
+
3
+ Searchtastic makes it possible to filter any collection of ActiveRecord models automatically based on any field,
4
+ including associated fields not even on the model itself. It's kind of awesome.
5
+
6
+ # Installation
7
+
8
+ In Rails 3, add this to your Gemfile and run the `bundle` command.
9
+
10
+ ```ruby
11
+ gem 'searchtastic'
12
+ ```
13
+
14
+ # Basic Usage
15
+
16
+ ### 1. Set up Your Models
17
+
18
+ Make a model searchable by providing an array of attributes to search on:
19
+
20
+ ```ruby
21
+ class User < ActiveRecord::Base
22
+ attr_accessible :name, :bio
23
+ has_one :club, class_name: Organization
24
+ searchable_by %w(name bio club.name)
25
+ end
26
+ ```
27
+
28
+ ### 2. Perform the Search
29
+
30
+ Searching works anywhere, but normally you'll search from within a controller action:
31
+
32
+ ```ruby
33
+ ...
34
+ def index
35
+ #@filter == "test"
36
+ @users = User.search(@filter)
37
+ ...
38
+ end
39
+ ...
40
+ ```
41
+
42
+ # To Do
43
+
44
+ * Search on Dates -- there's no good way to do this right now
45
+ * Search on combined fields, e.g. first_name + last_name
46
+ * Search on all accessible attributes shorthand
47
+
48
+ # Contributors
49
+
50
+ `searchtastic` is solely Pete Michaud's (me@petermichaud.com) fault, so blame him for everything.
51
+
52
+ # License
53
+
54
+ (The MIT License)
55
+
56
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
57
+ documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the
58
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
59
+ persons to whom the Software is furnished to do so, subject to the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
62
+ Software.
63
+
64
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
65
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
66
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
67
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,112 @@
1
+ require 'searchtastic/version'
2
+
3
+ # This module is automatically included in all ActiveRecords
4
+ module Searchtastic
5
+ module ActiveRecord
6
+
7
+ # Array of fields upon which it's possible to search
8
+ def fields
9
+ @fields || []
10
+ end
11
+
12
+ # Sets the searchable fields for a given model
13
+ # class User < ActiveRecord::Base
14
+ # search_fields %w(name email bio)
15
+ # end
16
+ #
17
+ def searchable_by *fields
18
+ self.fields = process_fields(fields)
19
+ end
20
+
21
+ # Called on an ActiveRelation containing the model
22
+ #
23
+ # filter = "Pete"
24
+ # @filtered_models = User.search(filter)
25
+ #
26
+ def search filter
27
+ if filter && self.fields.count
28
+ handle_joins(self.fields).where(build_filter(filter, self.fields))
29
+ else
30
+ scoped
31
+ end
32
+ end
33
+
34
+ # Callable on an instance or the call itself to detect whether .search() will have meaningful results
35
+ #
36
+ # User.search(@filter) if User.is_searchable?
37
+ #
38
+ def is_searchable?
39
+ self.fields.count < 0
40
+ end
41
+
42
+ private
43
+
44
+ # Set fields -- private, see searchable_by
45
+ def fields=(value)
46
+ @fields = value
47
+ end
48
+
49
+ # Fields can be specified with or without the model table name, but internally all
50
+ # fields need to be qualified by table name for disambiguation
51
+ #
52
+ # fields = %w(name email)
53
+ # process_fields(fields) => %w(users.name users.email)
54
+ #
55
+ def process_fields(fields)
56
+ fields.map { |field| field.to_s.include?('.') ? field.to_s : "#{self.table_name}.#{field}" }
57
+ end
58
+
59
+ # Before adding the where clauses, we have to make sure the right tables are joined
60
+ # into the query. We use .includes() instead of .joins() so we can get an OUTER JOIN
61
+ #
62
+ def handle_joins fields
63
+ ret = scoped
64
+ fields.each do |field|
65
+ assoc, table = field_table(field)
66
+ ret = ret.includes(assoc) unless table == self.table_name.to_sym
67
+ end
68
+ ret
69
+ end
70
+
71
+ # Get table name from association name
72
+ #
73
+ # class User < ActiveRecord::Base
74
+ # belongs_to :company, class_name: Organization
75
+ # searchable_by %w(name, email, company.name)
76
+ # end
77
+ #
78
+ # field_table('company.name') => [:companies, :organizations]
79
+ #
80
+ def field_table(field)
81
+ if field.include? '.'
82
+ assoc = field.split('.').first
83
+ if assoc != self.table_name
84
+ return assoc.to_sym, self.reflect_on_association(assoc.to_sym).table_name.to_sym
85
+ end
86
+ end
87
+
88
+ return nil, self.table_name
89
+
90
+ end
91
+
92
+ # Build the filter for the .where() clause in the search method
93
+ #
94
+ def build_filter filter, fields
95
+ where = [associations_to_tables(fields).map { |f| "#{f} like ?" }.join(" || ")]
96
+ fields.count.times { |n| where << "%#{filter}%" }
97
+ where
98
+ end
99
+
100
+ # Set the field to the right table and column name for the database
101
+ #
102
+ def associations_to_tables fields
103
+ fields.map do |field|
104
+ _, column = field.split('.')
105
+ "#{field_table(field)[1]}.#{column}"
106
+ end
107
+ end
108
+
109
+ end #ActiveRecord
110
+ end #Searchtastic
111
+
112
+ ActiveRecord::Base.extend Searchtastic::ActiveRecord
@@ -0,0 +1,3 @@
1
+ module Searchtastic
2
+ VERSION = '0.5.0'
3
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "searchtastic/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "searchtastic"
7
+ s.version = Searchtastic::VERSION
8
+ s.authors = ["Pete Michaud"]
9
+ s.email = ["me@petermichaud.com"]
10
+ s.homepage = "http://github.com/PeteMichaud/searchtastic"
11
+ s.summary = "Enables ActiveRecord Model Searching"
12
+ s.description = "Enables ActiveRecord Model Searching"
13
+ s.rubyforge_project = "searchtastic"
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["config", "lib"]
18
+
19
+ #s.add_dependency 'activesupport', '~> 3.2'
20
+ #s.add_dependency 'actionpack', '~> 3.2'
21
+
22
+ s.add_development_dependency 'rake', '~> 0.9.2'
23
+ s.add_development_dependency 'rspec', '~> 2.10'
24
+ s.add_development_dependency 'yard'
25
+ s.add_development_dependency 'minitest-rails', '~> 0.2'
26
+ s.add_development_dependency 'minitest', '~> 3.0' if RUBY_PLATFORM == "java"
27
+ end
@@ -0,0 +1,2 @@
1
+ require 'active_support/inflector'
2
+ require 'searchtastic'
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: searchtastic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Pete Michaud
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.2
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.10'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.10'
46
+ - !ruby/object:Gem::Dependency
47
+ name: yard
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: minitest-rails
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.2'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0.2'
78
+ description: Enables ActiveRecord Model Searching
79
+ email:
80
+ - me@petermichaud.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .rspec
87
+ - Gemfile
88
+ - Rakefile
89
+ - Readme.md
90
+ - lib/searchtastic.rb
91
+ - lib/searchtastic/version.rb
92
+ - searchtastic.gemspec
93
+ - spec/spec_helper.rb
94
+ homepage: http://github.com/PeteMichaud/searchtastic
95
+ licenses: []
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - config
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project: searchtastic
115
+ rubygems_version: 1.8.24
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: Enables ActiveRecord Model Searching
119
+ test_files:
120
+ - spec/spec_helper.rb