has_finder 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -1
- data/README.txt +98 -1
- data/lib/has_finder/has_finder.rb +1 -1
- data/lib/has_finder/version.rb +1 -1
- data/spec/rails/log/test.log +94 -0
- metadata +2 -2
data/History.txt
CHANGED
data/README.txt
CHANGED
@@ -1 +1,98 @@
|
|
1
|
-
|
1
|
+
HasFinder is an extension to ActiveRecord that makes it easier than ever to create custom find and count queries.
|
2
|
+
|
3
|
+
Let's start with an example. Suppose you have an Article model; some articles are published, some are popular. Let's declare finders for each of these notions. You may be tempted to write something like the following:
|
4
|
+
|
5
|
+
class Article < ActiveRecord::Base
|
6
|
+
def self.published
|
7
|
+
find(:all, :conditions => {:published => true})
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.popular
|
11
|
+
...
|
12
|
+
end
|
13
|
+
...
|
14
|
+
end
|
15
|
+
|
16
|
+
But there are serious limitations to this approach. How do you find articles that are BOTH popular and published? How can you easily paginate published articles?
|
17
|
+
|
18
|
+
# HasFinder Features
|
19
|
+
|
20
|
+
Let's define the equivalent finders using my new plugin, has_finder:
|
21
|
+
|
22
|
+
class Article < ActiveRecord::Base
|
23
|
+
has_finder :published, :conditions => {:published => true}
|
24
|
+
has_finder :popular, :conditions => ...
|
25
|
+
end
|
26
|
+
|
27
|
+
## Query Composition
|
28
|
+
|
29
|
+
Now, you can elegantly compose queries:
|
30
|
+
|
31
|
+
Article.published.popular
|
32
|
+
|
33
|
+
This will return all articles that are both popular and published.
|
34
|
+
|
35
|
+
## Calculations and Nested Finds
|
36
|
+
You can also easily paginate or call nested finders or do calculations:
|
37
|
+
|
38
|
+
Article.published.paginate(:page => 1)
|
39
|
+
Article.published.popular.count
|
40
|
+
Article.popular.find(:first)
|
41
|
+
Article.popular.find(:all, :conditions => {...})
|
42
|
+
|
43
|
+
## Works with ActiveRecord `has_many` and `has_many :through` Associations
|
44
|
+
Furthermore, without any additional work, these finders will work with ActiveRecord associations.
|
45
|
+
|
46
|
+
class User
|
47
|
+
has_many :articles
|
48
|
+
end
|
49
|
+
|
50
|
+
user.articles.popular.find(:first)
|
51
|
+
user.articles.published.popular.average(:view_count)
|
52
|
+
|
53
|
+
## Finders are extendable just like ActiveRecord Associations
|
54
|
+
|
55
|
+
class Article
|
56
|
+
has_finder :unpublished :conditions => {:published => false} do
|
57
|
+
def published_all
|
58
|
+
find(:all).map(&:publish)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Alternatively, you can use the :extend options:
|
64
|
+
|
65
|
+
class Article
|
66
|
+
has_finder :unpublished, :conditions => ..., :extend => MyExtensionModule
|
67
|
+
end
|
68
|
+
|
69
|
+
## Finders behave just like ActiveRecord Associations
|
70
|
+
|
71
|
+
For example, you can call #reload:
|
72
|
+
|
73
|
+
Article.published.popular.reload
|
74
|
+
|
75
|
+
## Finders can take parameters
|
76
|
+
|
77
|
+
class Car
|
78
|
+
has_finder :colored, lambda {|color| { :conditions => {:color => color} } }
|
79
|
+
end
|
80
|
+
|
81
|
+
Car.colored('red').paginate(:page => 1)
|
82
|
+
|
83
|
+
# What makes HasFinder better than alternatives like `scope_out` and `scoped_proxy`?
|
84
|
+
|
85
|
+
There are already two plugins similar to HasFinder: [`scope_out`](http://code.google.com/p/scope-out-rails) and [`scoped_proxy`](http://www.neotrivium.com/blog/2007/4/4/out_of_the_scope_of_scope_out?language=en-US). Both of them are excellent. In fact, Scoped Proxy was the model for HasFinder. Unfortunately, neither plugin provided all of the features I desired. Scope-Out lacks on-the-fly composition, a nice way to call a nested find, or the ability to do arbitrary calculations. Scoped Proxy is great, but it doesn't work with regular ActiveRecord Associations, it is not extendable like ActiveRecord associations, and it doesn't behave exactly like a regular ActiveRecord Association. Neither of them work out of the box with will_paginate. For all of these reasons and more, I rolled my own. It's now available as a gem.
|
86
|
+
|
87
|
+
# Installation
|
88
|
+
|
89
|
+
% gem install has_finder
|
90
|
+
|
91
|
+
# Usage
|
92
|
+
|
93
|
+
In environment.rb:
|
94
|
+
|
95
|
+
gem 'has_finder'
|
96
|
+
require 'has_finder'
|
97
|
+
|
98
|
+
See the examples above for usage.
|
@@ -25,7 +25,7 @@ module HasFinder
|
|
25
25
|
elsif proxy_finder.finders.include?(method)
|
26
26
|
finders[method].call(self, *args)
|
27
27
|
else
|
28
|
-
proxy_finder.with_scope :find => proxy_scope do
|
28
|
+
proxy_finder.send(:with_scope, { :find => proxy_scope }) do
|
29
29
|
proxy_finder.send(method, *args, &block)
|
30
30
|
end
|
31
31
|
end
|
data/lib/has_finder/version.rb
CHANGED
data/spec/rails/log/test.log
CHANGED
@@ -5818,3 +5818,97 @@ Spec::Rails::DSL::ViewExampleController: missing default helper path spec/rails/
|
|
5818
5818
|
[4;36;1mProperty Load (0.000189)[0m [0;1mSELECT * FROM properties WHERE (properties.being_id = 2) [0m
|
5819
5819
|
[4;35;1mProperty Load (0.000211)[0m [0mSELECT * FROM properties WHERE (( properties.being_id = 2 ) AND ( name LIKE 'r%' )) AND (properties.being_id = 2) [0m
|
5820
5820
|
[4;36;1mSQL (0.000097)[0m [0;1mROLLBACK[0m
|
5821
|
+
Spec::Rails::DSL::HelperEvalContextController: missing default helper path spec/rails/dsl/helper_eval_context_helper
|
5822
|
+
Spec::Rails::DSL::ViewExampleController: missing default helper path spec/rails/dsl/view_example_helper
|
5823
|
+
[4;36;1mSQL (0.037990)[0m [0;1mSET SQL_AUTO_IS_NULL=0[0m
|
5824
|
+
[4;35;1mSQL (0.000119)[0m [0mBEGIN[0m
|
5825
|
+
[4;36;1mBeing Load (0.004143)[0m [0;1mSELECT * FROM beings [0m
|
5826
|
+
[4;35;1mBeing Columns (0.013376)[0m [0mSHOW FIELDS FROM beings[0m
|
5827
|
+
[4;36;1mSQL (0.167181)[0m [0;1mINSERT INTO beings (`country`, `race`) VALUES(NULL, NULL)[0m
|
5828
|
+
[4;35;1mBeing Load (0.000335)[0m [0mSELECT * FROM beings [0m
|
5829
|
+
[4;36;1mBeing Load (0.000250)[0m [0;1mSELECT * FROM beings [0m
|
5830
|
+
[4;35;1mSQL (0.005772)[0m [0mROLLBACK[0m
|
5831
|
+
[4;36;1mSQL (0.000080)[0m [0;1mBEGIN[0m
|
5832
|
+
[4;35;1mBeing Load (0.000290)[0m [0mSELECT * FROM beings [0m
|
5833
|
+
[4;36;1mBeing Load (0.000245)[0m [0;1mSELECT * FROM beings [0m
|
5834
|
+
[4;35;1mBeing Load (0.000248)[0m [0mSELECT * FROM beings LIMIT 1[0m
|
5835
|
+
[4;36;1mBeing Load (0.000225)[0m [0;1mSELECT * FROM beings LIMIT 1[0m
|
5836
|
+
[4;35;1mBeing Load (0.000237)[0m [0mSELECT * FROM beings [0m
|
5837
|
+
[4;36;1mSQL (0.033188)[0m [0;1mSELECT count(*) AS count_all FROM beings [0m
|
5838
|
+
[4;35;1mSQL (0.000257)[0m [0mSELECT count(*) AS count_all FROM beings [0m
|
5839
|
+
[4;36;1mBeing Load (0.000259)[0m [0;1mSELECT * FROM beings [0m
|
5840
|
+
[4;35;1mSQL (0.009529)[0m [0mSELECT avg(id) AS avg_id FROM beings [0m
|
5841
|
+
[4;36;1mSQL (0.000269)[0m [0;1mSELECT avg(id) AS avg_id FROM beings [0m
|
5842
|
+
[4;35;1mSQL (0.000165)[0m [0mROLLBACK[0m
|
5843
|
+
[4;36;1mSQL (0.000415)[0m [0;1mBEGIN[0m
|
5844
|
+
[4;35;1mBeing Load (0.000260)[0m [0mSELECT * FROM beings [0m
|
5845
|
+
[4;36;1mBeing Load (0.000217)[0m [0;1mSELECT * FROM beings [0m
|
5846
|
+
[4;35;1mBeing Load (0.000218)[0m [0mSELECT * FROM beings [0m
|
5847
|
+
[4;36;1mBeing Load (0.000220)[0m [0;1mSELECT * FROM beings [0m
|
5848
|
+
[4;35;1mBeing Load (0.000215)[0m [0mSELECT * FROM beings [0m
|
5849
|
+
[4;36;1mBeing Load (0.000213)[0m [0;1mSELECT * FROM beings [0m
|
5850
|
+
[4;35;1mSQL (0.000145)[0m [0mROLLBACK[0m
|
5851
|
+
[4;36;1mSQL (0.000084)[0m [0;1mBEGIN[0m
|
5852
|
+
[4;35;1mBeing Load (0.001138)[0m [0mSELECT * FROM beings WHERE (beings.`country` = 'greece') [0m
|
5853
|
+
[4;36;1mBeing Load (0.000217)[0m [0;1mSELECT * FROM beings WHERE (beings.`id` = 1) [0m
|
5854
|
+
[4;35;1mBeing Load (0.000187)[0m [0mSELECT * FROM beings WHERE (beings.`id` = 3) [0m
|
5855
|
+
[4;36;1mBeing Load (0.000332)[0m [0;1mSELECT * FROM beings WHERE (beings.`race` = 'mortal') [0m
|
5856
|
+
[4;35;1mBeing Load (0.000200)[0m [0mSELECT * FROM beings WHERE (beings.`id` = 2) [0m
|
5857
|
+
[4;36;1mSQL (0.000102)[0m [0;1mROLLBACK[0m
|
5858
|
+
[4;35;1mSQL (0.000319)[0m [0mBEGIN[0m
|
5859
|
+
[4;36;1mBeing Load (0.000223)[0m [0;1mSELECT * FROM beings WHERE (beings.`country` = 'greece') LIMIT 1[0m
|
5860
|
+
[4;35;1mBeing Load (0.000192)[0m [0mSELECT * FROM beings WHERE (beings.`id` = 1) [0m
|
5861
|
+
[4;36;1mSQL (0.000080)[0m [0;1mROLLBACK[0m
|
5862
|
+
[4;35;1mSQL (0.000240)[0m [0mBEGIN[0m
|
5863
|
+
[4;36;1mBeing Load (0.000213)[0m [0;1mSELECT * FROM beings WHERE (beings.`country` = 'greece') [0m
|
5864
|
+
[4;35;1mBeing Load (0.025420)[0m [0mSELECT * FROM beings WHERE (( ( beings.`country` = 'greece' ) AND ( beings.`race` = 'mortal' ) ) AND ( beings.`country` = 'greece' )) [0m
|
5865
|
+
[4;36;1mBeing Load (0.000303)[0m [0;1mSELECT * FROM beings WHERE (beings.`id` = 1) [0m
|
5866
|
+
[4;35;1mSQL (0.000167)[0m [0mROLLBACK[0m
|
5867
|
+
[4;36;1mSQL (0.000085)[0m [0;1mBEGIN[0m
|
5868
|
+
[4;35;1mBeing Load (0.000283)[0m [0mSELECT * FROM beings WHERE (beings.`country` = 'greece') [0m
|
5869
|
+
[4;36;1mBeing Load (0.000189)[0m [0;1mSELECT * FROM beings WHERE (beings.`id` = 1) [0m
|
5870
|
+
[4;35;1mBeing Load (0.000168)[0m [0mSELECT * FROM beings WHERE (beings.`id` = 3) [0m
|
5871
|
+
[4;36;1mBeing Load (0.000197)[0m [0;1mSELECT * FROM beings WHERE (beings.`country` = 'greece') LIMIT 1[0m
|
5872
|
+
[4;35;1mSQL (0.000098)[0m [0mROLLBACK[0m
|
5873
|
+
[4;36;1mSQL (0.000083)[0m [0;1mBEGIN[0m
|
5874
|
+
[4;35;1mSQL (0.000084)[0m [0mROLLBACK[0m
|
5875
|
+
[4;36;1mSQL (0.000262)[0m [0;1mBEGIN[0m
|
5876
|
+
[4;35;1mSQL (0.000087)[0m [0mROLLBACK[0m
|
5877
|
+
[4;36;1mSQL (0.000259)[0m [0;1mBEGIN[0m
|
5878
|
+
[4;35;1mSQL (0.000085)[0m [0mROLLBACK[0m
|
5879
|
+
[4;36;1mSQL (0.000064)[0m [0;1mBEGIN[0m
|
5880
|
+
[4;35;1mProperty Load (0.000361)[0m [0mSELECT * FROM properties WHERE (name LIKE 'r%') [0m
|
5881
|
+
[4;36;1mProperty Columns (0.001772)[0m [0;1mSHOW FIELDS FROM properties[0m
|
5882
|
+
[4;35;1mProperty Load (0.000655)[0m [0mSELECT * FROM properties WHERE (properties.`id` = 1) [0m
|
5883
|
+
[4;36;1mProperty Load (0.000228)[0m [0;1mSELECT * FROM properties WHERE (properties.`id` = 2) [0m
|
5884
|
+
[4;35;1mProperty Load (0.000213)[0m [0mSELECT * FROM properties WHERE (properties.`id` = 3) [0m
|
5885
|
+
[4;36;1mBeing Load (0.000238)[0m [0;1mSELECT * FROM beings WHERE (beings.`id` = 2) [0m
|
5886
|
+
[4;35;1mProperty Load (0.000230)[0m [0mSELECT * FROM properties WHERE (properties.`id` = 4) [0m
|
5887
|
+
[4;36;1mProperty Load (0.000244)[0m [0;1mSELECT * FROM properties WHERE (properties.being_id = 2) [0m
|
5888
|
+
[4;35;1mProperty Load (0.000266)[0m [0mSELECT * FROM properties WHERE (( properties.being_id = 2 ) AND ( name LIKE 'r%' )) AND (properties.being_id = 2) [0m
|
5889
|
+
[4;36;1mSQL (0.000145)[0m [0;1mROLLBACK[0m
|
5890
|
+
Spec::Rails::DSL::HelperEvalContextController: missing default helper path spec/rails/dsl/helper_eval_context_helper
|
5891
|
+
Spec::Rails::DSL::ViewExampleController: missing default helper path spec/rails/dsl/view_example_helper
|
5892
|
+
[4;36;1mSQL (0.000138)[0m [0;1mSET SQL_AUTO_IS_NULL=0[0m
|
5893
|
+
[4;35;1mSQL (0.000109)[0m [0mBEGIN[0m
|
5894
|
+
[4;36;1mSQL (0.000169)[0m [0;1mROLLBACK[0m
|
5895
|
+
[4;35;1mSQL (0.000179)[0m [0mBEGIN[0m
|
5896
|
+
[4;36;1mSQL (0.000168)[0m [0;1mROLLBACK[0m
|
5897
|
+
[4;35;1mSQL (0.000319)[0m [0mBEGIN[0m
|
5898
|
+
[4;36;1mSQL (0.000166)[0m [0;1mROLLBACK[0m
|
5899
|
+
[4;35;1mSQL (0.000179)[0m [0mBEGIN[0m
|
5900
|
+
[4;36;1mSQL (0.000163)[0m [0;1mROLLBACK[0m
|
5901
|
+
[4;35;1mSQL (0.000299)[0m [0mBEGIN[0m
|
5902
|
+
[4;36;1mSQL (0.000187)[0m [0;1mROLLBACK[0m
|
5903
|
+
[4;35;1mSQL (0.000328)[0m [0mBEGIN[0m
|
5904
|
+
[4;36;1mSQL (0.000173)[0m [0;1mROLLBACK[0m
|
5905
|
+
[4;35;1mSQL (0.000124)[0m [0mBEGIN[0m
|
5906
|
+
[4;36;1mSQL (0.000191)[0m [0;1mROLLBACK[0m
|
5907
|
+
[4;35;1mSQL (0.000179)[0m [0mBEGIN[0m
|
5908
|
+
[4;36;1mSQL (0.000071)[0m [0;1mROLLBACK[0m
|
5909
|
+
[4;35;1mSQL (0.000246)[0m [0mBEGIN[0m
|
5910
|
+
[4;36;1mSQL (0.000073)[0m [0;1mROLLBACK[0m
|
5911
|
+
[4;35;1mSQL (0.000201)[0m [0mBEGIN[0m
|
5912
|
+
[4;36;1mSQL (0.000072)[0m [0;1mROLLBACK[0m
|
5913
|
+
[4;35;1mSQL (0.000146)[0m [0mBEGIN[0m
|
5914
|
+
[4;36;1mSQL (0.000179)[0m [0;1mROLLBACK[0m
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: has_finder
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.1.2
|
7
|
+
date: 2007-09-02 00:00:00 -07:00
|
8
8
|
summary: description of gem
|
9
9
|
require_paths:
|
10
10
|
- lib
|