findable_by 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +31 -7
- data/lib/findable_by.rb +19 -7
- data/lib/findable_by/finders/scope_finder.rb +11 -0
- data/lib/findable_by/version.rb +1 -1
- data/test/findable_by_test.rb +11 -5
- data/test/schema/schema.rb +6 -1
- data/test/support/models.rb +8 -4
- metadata +5 -4
data/README.markdown
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
findable_by
|
2
2
|
=
|
3
3
|
|
4
|
-
findable_by is a simple Rails 3 plugin to improve a way how you search for records. You can pass the search form parameters directly to the find_with method in your relation,
|
4
|
+
findable_by is a simple Rails 3 plugin to improve a way how you search for records. You can pass the search form parameters directly to the find_with method in your relation, by example. The plugin will take care to build a correct query in a safer way. This plugin doesn't modify the default behaviour of query engine of Rails3, but gives a new way to do your queries. You can use the both ways at same time without problems.
|
5
|
+
|
6
|
+
This plugin is designed to improve a way how to find records when you have a search forms, and in a standardized, cleaner and safer way to link the parameters from search form to model that declares how to search them.
|
5
7
|
|
6
8
|
See below how it's works.
|
7
9
|
|
@@ -15,32 +17,54 @@ In your Gemfile:
|
|
15
17
|
Usage
|
16
18
|
-
|
17
19
|
|
20
|
+
In your model you need to declare what the attributes you want to make "findable". For each, you can declare the way how it is "findable". You can declare more to one attribute in same line that use same way.
|
21
|
+
|
18
22
|
class Person < ActiveRecord::Base
|
19
23
|
scope :gender, proc { |value| where(:gender => value) }
|
24
|
+
scope :by_department_name, proc { |value| joins(:department).where(:department => { :name => value }) }
|
20
25
|
|
21
26
|
findable_by :first_name, :using => :like
|
22
27
|
findable_by :last_name, :using => UpcaseFinder
|
23
28
|
findable_by :primary_contact_id, :using => :equals
|
24
29
|
findable_by :number1_fan, :using => proc { |attribute, value| where("1=1") }
|
25
30
|
findable_by :gender, :using => proc { |attribute, value| gender(value) }
|
26
|
-
findable_by :age,
|
27
|
-
|
31
|
+
findable_by :age, :birth_date, :using => :between, :with => [ :min, :max ]
|
32
|
+
|
33
|
+
belongs_to :department
|
34
|
+
|
35
|
+
# When department_name is setted "findable_by" will call :by_department_name named scope
|
36
|
+
# passing the value by parameter.
|
37
|
+
findable_by :department_name, :through => :by_department_name
|
28
38
|
end
|
29
39
|
|
30
40
|
And now you can search:
|
31
41
|
|
32
42
|
relation = Person.scoped
|
33
|
-
relation = relation.find_with(params[:search])
|
34
|
-
|
43
|
+
relation = relation.find_with(params[:search]) # :search => { :first_name => "Jose", :last_name => "Lito",
|
44
|
+
# :age => { :min => 25, :max => 45 } }
|
45
|
+
|
46
|
+
relation.where(:gender => 'M').limit(1).all
|
35
47
|
|
36
|
-
|
48
|
+
You can create your own finders. Just create a class in your lib/ that extends Finder and respond_to "build_condition". Example, if you need to create a finder that upcase the value before creation the condition, you finder looks like this:
|
49
|
+
|
50
|
+
class UpcaseFinder < Finder
|
51
|
+
def build_condition(relation, attribute, value, params)
|
52
|
+
relation.where(attribute => value.upcase!)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
You can do much more! By example, create finders that sanitize or normalize inputs, scaling your productivity. In some cases too, you need to call a DB-specific function in where clause, you can write and Finder to do it and maintain your model more cleaner.
|
57
|
+
|
58
|
+
Help wanted for...
|
37
59
|
-
|
38
60
|
|
39
|
-
|
61
|
+
To make a better documentation and improve testing. Pull requests are welcome.
|
40
62
|
|
41
63
|
Bugs and Feedback
|
42
64
|
-
|
43
65
|
|
66
|
+
If you see any bugs or if you have a comment to do, please, write a issue here:
|
67
|
+
|
44
68
|
http://github.com/thiagomoretto/findable_by/issues
|
45
69
|
|
46
70
|
MIT License. Copyright 2010.
|
data/lib/findable_by.rb
CHANGED
@@ -49,16 +49,28 @@ module FindableBy
|
|
49
49
|
def findable_by(*attr_names)
|
50
50
|
options = attr_names.extract_options!
|
51
51
|
options.merge!(:attributes => attr_names.flatten)
|
52
|
-
options[:using] = :equals if not options.key?(:using)
|
53
52
|
options[:attributes].each do |attribute|
|
54
|
-
|
53
|
+
using, through = options[:using], options[:through]
|
54
|
+
if not using.blank? and not through.blank?
|
55
|
+
raise ArgumentError, "You cannot use :using and :through at same time"
|
56
|
+
end
|
55
57
|
|
56
|
-
if
|
57
|
-
|
58
|
-
|
59
|
-
self._finders[attribute] =
|
58
|
+
options[:using] = :equals if through.blank? and using.blank?
|
59
|
+
|
60
|
+
if not through.blank?
|
61
|
+
self._finders[attribute] = ScopeFinder.new(options, through)
|
60
62
|
else
|
61
|
-
self._finders[attribute] =
|
63
|
+
self._finders[attribute] =
|
64
|
+
case using
|
65
|
+
when Class
|
66
|
+
using.send(:new, options)
|
67
|
+
when Proc
|
68
|
+
ProcFinder.new(options, using)
|
69
|
+
when Symbol
|
70
|
+
Kernel.const_get("#{options[:using]}_finder".classify).new(options)
|
71
|
+
else
|
72
|
+
raise ArgumentError, ":using must be: a Class, a Proc or a Symbol"
|
73
|
+
end
|
62
74
|
end
|
63
75
|
end
|
64
76
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ScopeFinder < Finder
|
2
|
+
attr_accessor :named_scope
|
3
|
+
def initialize(options, named_scope)
|
4
|
+
super(options)
|
5
|
+
self.named_scope = named_scope
|
6
|
+
end
|
7
|
+
|
8
|
+
def build_condition(relation, attribute, value, params)
|
9
|
+
relation.send(named_scope, value) if relation.respond_to?(named_scope)
|
10
|
+
end
|
11
|
+
end
|
data/lib/findable_by/version.rb
CHANGED
data/test/findable_by_test.rb
CHANGED
@@ -6,13 +6,13 @@ class FindableByTest < ActiveRecord::TestCase
|
|
6
6
|
|
7
7
|
test "should generate a SQL to find a person by first name using like" do
|
8
8
|
with_scoped(Person) do |person|
|
9
|
-
assert_not_nil person.find_with(:first_name => "OMG!").to_sql
|
9
|
+
assert_not_nil person.find_with(:first_name => "OMG!").to_sql =~ /LIKE/
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
test "should generate a SQL to find a person using a proc" do
|
14
14
|
with_scoped(Person) do |person|
|
15
|
-
assert_not_nil person.find_with(:number1_fan => "Don't care").to_sql
|
15
|
+
assert_not_nil person.find_with(:number1_fan => "Don't care").to_sql =~ /1=1/
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -25,13 +25,13 @@ class FindableByTest < ActiveRecord::TestCase
|
|
25
25
|
|
26
26
|
test "should generate a SQL to find a person calling 'find_with' chained" do
|
27
27
|
with_scoped(Person) do |person|
|
28
|
-
assert_not_nil person.find_with(:first_name => "OMG!").find_with(:gender => 'F').to_sql
|
28
|
+
assert_not_nil person.find_with(:first_name => "OMG!").find_with(:gender => 'F').to_sql =~ /first_name/
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
test "should generate a SQL to find a person by primary_contact_id using equals" do
|
33
33
|
with_scoped(Person) do |person|
|
34
|
-
assert_not_nil person.find_with(:primary_contact_id => 1).to_sql
|
34
|
+
assert_not_nil person.find_with(:primary_contact_id => 1).to_sql =~ /primary_contact_id/
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -54,9 +54,15 @@ class FindableByTest < ActiveRecord::TestCase
|
|
54
54
|
assert person.find_with(params).to_sql =~ /BETWEEN/
|
55
55
|
end
|
56
56
|
end
|
57
|
+
|
58
|
+
test "should generate a SQL to find people by department name using like" do
|
59
|
+
with_scoped(Person) do |person|
|
60
|
+
assert_not_nil person.find_with(:department_name => "hr").to_sql =~ /"department"."name" = 'hr'/
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
57
64
|
private
|
58
65
|
def with_scoped(model, &block)
|
59
66
|
block.call(model.send(:scoped))
|
60
67
|
end
|
61
|
-
|
62
68
|
end
|
data/test/schema/schema.rb
CHANGED
@@ -5,9 +5,14 @@ ActiveRecord::Schema.define do
|
|
5
5
|
t.string :last_name
|
6
6
|
t.references :primary_contact
|
7
7
|
t.string :gender, :limit => 1
|
8
|
-
t.
|
8
|
+
t.integer :number1_fan
|
9
|
+
t.references :department
|
9
10
|
t.integer :age, :limit => 3
|
10
11
|
t.integer :lock_version, :null => false, :default => 0
|
11
12
|
end
|
12
13
|
|
14
|
+
create_table :departments, :force => true do |t|
|
15
|
+
t.string :name, :null => false
|
16
|
+
end
|
17
|
+
|
13
18
|
end
|
data/test/support/models.rb
CHANGED
@@ -6,15 +6,19 @@ end
|
|
6
6
|
|
7
7
|
class Person < ActiveRecord::Base
|
8
8
|
scope :gender, proc { |value| where(:gender => 'F') }
|
9
|
+
scope :by_department_name, proc { |value| joins(:department).where(:department => { :name => value }) }
|
9
10
|
|
10
11
|
findable_by :first_name, :using => :like
|
11
12
|
findable_by :last_name, :using => UpcaseFinder
|
12
13
|
findable_by :primary_contact_id, :using => :equals
|
13
14
|
findable_by :number1_fan, :using => proc { |attribute, value| where("1=1") }
|
14
|
-
findable_by :gender, :
|
15
|
+
findable_by :gender, :through => :gender
|
15
16
|
findable_by :age, :using => :between, :with => [ :min, :max ]
|
16
17
|
findable_by :birth_date, :using => :between, :with => [ :min, :max ]
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
belongs_to :department
|
20
|
+
|
21
|
+
findable_by :department_name, :through => :by_department_name
|
22
|
+
end
|
23
|
+
|
24
|
+
class Department < ActiveRecord::Base; end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: findable_by
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Thiago Moretto
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-17 00:00:00 -03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- lib/findable_by/finders/equals_finder.rb
|
35
35
|
- lib/findable_by/finders/like_finder.rb
|
36
36
|
- lib/findable_by/finders/proc_finder.rb
|
37
|
+
- lib/findable_by/finders/scope_finder.rb
|
37
38
|
- lib/findable_by/version.rb
|
38
39
|
- README.markdown
|
39
40
|
- test/connection/native_sqlite3/in_memory_connection.rb
|