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 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, and the plugin will take care to build a correct query in a safer way.
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, :using => :between, :with => [ :min, :max ]
27
- findable_by :birth_date, :using => :between, :with => [ :min, :max ]
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
- relation.all
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
- TODO
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
- README and some documentation.
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
- using_what = options[:using]
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 using_what.is_a?(Class)
57
- self._finders[attribute] = using_what.new(options)
58
- elsif using_what.is_a?(Proc)
59
- self._finders[attribute] = ProcFinder.new(options, using_what)
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] = Kernel.const_get("#{options[:using]}_finder".classify).new(options)
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
@@ -1,3 +1,3 @@
1
1
  module FindableBy
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.1.1".freeze
3
3
  end
@@ -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
@@ -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.references :number1_fan
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
@@ -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, :using => proc { |attribute, value| gender(value) }
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
- # TODO: findable_by :gender, :through => :gender # uses scope :gender
19
- # TODO: findable_by :gender # uses (:using => :equals)
20
- end
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: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
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-12 00:00:00 -03:00
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