watson-acts_as_ferret 0.4.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +104 -0
- data/acts_as_ferret.gemspec +58 -0
- data/bin/aaf_install +29 -0
- data/config/ferret_server.yml +24 -0
- data/doc/README.win32 +23 -0
- data/doc/demo/README +154 -0
- data/doc/demo/README_DEMO +23 -0
- data/doc/demo/Rakefile +10 -0
- data/doc/demo/app/controllers/admin/backend_controller.rb +14 -0
- data/doc/demo/app/controllers/admin_area_controller.rb +4 -0
- data/doc/demo/app/controllers/application.rb +5 -0
- data/doc/demo/app/controllers/contents_controller.rb +49 -0
- data/doc/demo/app/controllers/searches_controller.rb +8 -0
- data/doc/demo/app/helpers/admin/backend_helper.rb +2 -0
- data/doc/demo/app/helpers/application_helper.rb +3 -0
- data/doc/demo/app/helpers/content_helper.rb +2 -0
- data/doc/demo/app/helpers/search_helper.rb +2 -0
- data/doc/demo/app/models/comment.rb +48 -0
- data/doc/demo/app/models/content.rb +12 -0
- data/doc/demo/app/models/content_base.rb +28 -0
- data/doc/demo/app/models/search.rb +19 -0
- data/doc/demo/app/models/shared_index1.rb +3 -0
- data/doc/demo/app/models/shared_index2.rb +3 -0
- data/doc/demo/app/models/special_content.rb +3 -0
- data/doc/demo/app/models/stats.rb +20 -0
- data/doc/demo/app/views/admin/backend/search.rhtml +18 -0
- data/doc/demo/app/views/contents/_form.rhtml +10 -0
- data/doc/demo/app/views/contents/edit.rhtml +9 -0
- data/doc/demo/app/views/contents/index.rhtml +24 -0
- data/doc/demo/app/views/contents/new.rhtml +8 -0
- data/doc/demo/app/views/contents/show.rhtml +8 -0
- data/doc/demo/app/views/layouts/application.html.erb +17 -0
- data/doc/demo/app/views/searches/_content.html.erb +2 -0
- data/doc/demo/app/views/searches/search.html.erb +20 -0
- data/doc/demo/config/boot.rb +109 -0
- data/doc/demo/config/database.yml +38 -0
- data/doc/demo/config/environment.rb +69 -0
- data/doc/demo/config/environments/development.rb +16 -0
- data/doc/demo/config/environments/production.rb +19 -0
- data/doc/demo/config/environments/test.rb +21 -0
- data/doc/demo/config/ferret_server.yml +18 -0
- data/doc/demo/config/lighttpd.conf +40 -0
- data/doc/demo/config/routes.rb +9 -0
- data/doc/demo/db/development_structure.sql +15 -0
- data/doc/demo/db/migrate/001_initial_migration.rb +18 -0
- data/doc/demo/db/migrate/002_add_type_to_contents.rb +9 -0
- data/doc/demo/db/migrate/003_create_shared_index1s.rb +11 -0
- data/doc/demo/db/migrate/004_create_shared_index2s.rb +11 -0
- data/doc/demo/db/migrate/005_special_field.rb +9 -0
- data/doc/demo/db/migrate/006_create_stats.rb +15 -0
- data/doc/demo/db/schema.sql +18 -0
- data/doc/demo/db/schema.sqlite +14 -0
- data/doc/demo/doc/README_FOR_APP +2 -0
- data/doc/demo/doc/howto.txt +70 -0
- data/doc/demo/public/404.html +8 -0
- data/doc/demo/public/500.html +8 -0
- data/doc/demo/public/dispatch.cgi +10 -0
- data/doc/demo/public/dispatch.fcgi +24 -0
- data/doc/demo/public/dispatch.rb +10 -0
- data/doc/demo/public/favicon.ico +0 -0
- data/doc/demo/public/images/rails.png +0 -0
- data/doc/demo/public/index.html +277 -0
- data/doc/demo/public/robots.txt +1 -0
- data/doc/demo/public/stylesheets/scaffold.css +74 -0
- data/doc/demo/script/about +3 -0
- data/doc/demo/script/breakpointer +3 -0
- data/doc/demo/script/console +3 -0
- data/doc/demo/script/destroy +3 -0
- data/doc/demo/script/ferret_server +10 -0
- data/doc/demo/script/generate +3 -0
- data/doc/demo/script/performance/benchmarker +3 -0
- data/doc/demo/script/performance/profiler +3 -0
- data/doc/demo/script/plugin +3 -0
- data/doc/demo/script/process/inspector +3 -0
- data/doc/demo/script/process/reaper +3 -0
- data/doc/demo/script/process/spawner +3 -0
- data/doc/demo/script/process/spinner +3 -0
- data/doc/demo/script/runner +3 -0
- data/doc/demo/script/server +3 -0
- data/doc/demo/test/fixtures/comments.yml +12 -0
- data/doc/demo/test/fixtures/contents.yml +13 -0
- data/doc/demo/test/fixtures/remote_contents.yml +9 -0
- data/doc/demo/test/fixtures/shared_index1s.yml +7 -0
- data/doc/demo/test/fixtures/shared_index2s.yml +7 -0
- data/doc/demo/test/functional/admin/backend_controller_test.rb +35 -0
- data/doc/demo/test/functional/contents_controller_test.rb +81 -0
- data/doc/demo/test/functional/searches_controller_test.rb +71 -0
- data/doc/demo/test/smoke/drb_smoke_test.rb +321 -0
- data/doc/demo/test/smoke/process_stats.rb +21 -0
- data/doc/demo/test/test_helper.rb +30 -0
- data/doc/demo/test/unit/comment_test.rb +217 -0
- data/doc/demo/test/unit/content_test.rb +705 -0
- data/doc/demo/test/unit/ferret_result_test.rb +24 -0
- data/doc/demo/test/unit/multi_index_test.rb +329 -0
- data/doc/demo/test/unit/remote_index_test.rb +23 -0
- data/doc/demo/test/unit/shared_index1_test.rb +108 -0
- data/doc/demo/test/unit/shared_index2_test.rb +13 -0
- data/doc/demo/test/unit/sort_test.rb +21 -0
- data/doc/demo/test/unit/special_content_test.rb +25 -0
- data/doc/demo/vendor/plugins/will_paginate/LICENSE +18 -0
- data/doc/demo/vendor/plugins/will_paginate/README +108 -0
- data/doc/demo/vendor/plugins/will_paginate/Rakefile +23 -0
- data/doc/demo/vendor/plugins/will_paginate/init.rb +21 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/collection.rb +45 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb +44 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/finder.rb +159 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb +95 -0
- data/doc/demo/vendor/plugins/will_paginate/test/array_pagination_test.rb +23 -0
- data/doc/demo/vendor/plugins/will_paginate/test/boot.rb +27 -0
- data/doc/demo/vendor/plugins/will_paginate/test/console +10 -0
- data/doc/demo/vendor/plugins/will_paginate/test/finder_test.rb +219 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/admin.rb +3 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/companies.yml +24 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/company.rb +23 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/developer.rb +11 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml +13 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/project.rb +4 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/projects.yml +7 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/replies.yml +20 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/reply.rb +5 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/schema.sql +44 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/topic.rb +19 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/topics.yml +30 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/user.rb +2 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/users.yml +35 -0
- data/doc/demo/vendor/plugins/will_paginate/test/helper.rb +42 -0
- data/doc/demo/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb +64 -0
- data/doc/demo/vendor/plugins/will_paginate/test/lib/load_fixtures.rb +10 -0
- data/doc/demo/vendor/plugins/will_paginate/test/pagination_test.rb +136 -0
- data/doc/monit-example +22 -0
- data/init.rb +24 -0
- data/install.rb +18 -0
- data/lib/act_methods.rb +147 -0
- data/lib/acts_as_ferret.rb +593 -0
- data/lib/ar_mysql_auto_reconnect_patch.rb +41 -0
- data/lib/blank_slate.rb +54 -0
- data/lib/bulk_indexer.rb +56 -0
- data/lib/class_methods.rb +279 -0
- data/lib/ferret_extensions.rb +192 -0
- data/lib/ferret_find_methods.rb +142 -0
- data/lib/ferret_result.rb +58 -0
- data/lib/ferret_server.rb +238 -0
- data/lib/index.rb +99 -0
- data/lib/instance_methods.rb +172 -0
- data/lib/local_index.rb +202 -0
- data/lib/more_like_this.rb +217 -0
- data/lib/multi_index.rb +133 -0
- data/lib/rdig_adapter.rb +149 -0
- data/lib/remote_functions.rb +43 -0
- data/lib/remote_index.rb +54 -0
- data/lib/remote_multi_index.rb +20 -0
- data/lib/search_results.rb +50 -0
- data/lib/server_manager.rb +71 -0
- data/lib/unix_daemon.rb +86 -0
- data/lib/without_ar.rb +52 -0
- data/recipes/aaf_recipes.rb +116 -0
- data/script/ferret_daemon +94 -0
- data/script/ferret_server +12 -0
- data/script/ferret_service +178 -0
- data/tasks/ferret.rake +39 -0
- metadata +246 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class SharedIndex2Test < Test::Unit::TestCase
|
4
|
+
fixtures :shared_index2s, :shared_index1s
|
5
|
+
|
6
|
+
def setup
|
7
|
+
SharedIndex1.rebuild_index
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_query_for_record
|
11
|
+
assert_match /SharedIndex2/, shared_index2s(:first).query_for_record.to_s
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class SortTest < Test::Unit::TestCase
|
4
|
+
include Ferret::Search
|
5
|
+
|
6
|
+
def test_sort_marshalling
|
7
|
+
[ Sort.new,
|
8
|
+
Sort.new( [], :reverse => true) ,
|
9
|
+
Sort.new([ Ferret::Search::SortField.new(:id, :reverse => true),
|
10
|
+
Ferret::Search::SortField::SCORE,
|
11
|
+
Ferret::Search::SortField::DOC_ID ],
|
12
|
+
:reverse => true),
|
13
|
+
Sort.new([ Ferret::Search::SortField.new(:id),
|
14
|
+
Ferret::Search::SortField::SCORE_REV,
|
15
|
+
Ferret::Search::SortField::DOC_ID_REV ])
|
16
|
+
].each do |sort|
|
17
|
+
assert_equal sort.to_s, Sort._load(sort._dump(0)).to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class SpecialContentTest < Test::Unit::TestCase
|
4
|
+
include Ferret::Index
|
5
|
+
include Ferret::Search
|
6
|
+
fixtures :contents, :comments
|
7
|
+
|
8
|
+
def setup
|
9
|
+
ContentBase.rebuild_index
|
10
|
+
Comment.rebuild_index
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_class_index_dir
|
14
|
+
assert SpecialContent.aaf_configuration[:index_dir] =~ %r{^#{RAILS_ROOT}/index/test/content_base}
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_find_with_ferret
|
18
|
+
contents_from_ferret = SpecialContent.find_with_ferret('single table')
|
19
|
+
assert_equal 1, contents_from_ferret.size
|
20
|
+
assert_equal ContentBase.find(3), contents_from_ferret.first
|
21
|
+
contents_from_ferret = SpecialContent.find_with_ferret('title')
|
22
|
+
assert contents_from_ferret.empty?
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2007 PJ Hyett and Mislav Marohnić
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,108 @@
|
|
1
|
+
= WillPaginate
|
2
|
+
|
3
|
+
Quick quiz: Where does pagination logic belong?
|
4
|
+
|
5
|
+
a) in the model;
|
6
|
+
b) in the controller;
|
7
|
+
c) in views;
|
8
|
+
d) all of the above.
|
9
|
+
|
10
|
+
We think you know the answer (if you think hard enough).
|
11
|
+
|
12
|
+
This plugin makes magic happen. You *will* paginate!
|
13
|
+
|
14
|
+
|
15
|
+
== Example usage:
|
16
|
+
|
17
|
+
Use a paginate finder in the controller:
|
18
|
+
|
19
|
+
@posts = Post.paginate_by_board_id @board.id, :page => params[:page]
|
20
|
+
|
21
|
+
Yeah, +paginate+ works just like +find+ -- it just doesn't fetch all the records.
|
22
|
+
Just don't forget to tell it which page you want!
|
23
|
+
|
24
|
+
Render the posts in your view like you would normally do. When you need to render
|
25
|
+
pagination, just stick this in:
|
26
|
+
|
27
|
+
<%= will_paginate @posts %>
|
28
|
+
|
29
|
+
You're done. (Copy and paste the example fancy CSS styles from the bottom.)
|
30
|
+
|
31
|
+
How does it know how much items to fetch per page? It asks your model by calling
|
32
|
+
+Post.per_page+. You can define it like this:
|
33
|
+
|
34
|
+
class Post < ActiveRecord::Base
|
35
|
+
cattr_reader :per_page
|
36
|
+
@@per_page = 50
|
37
|
+
end
|
38
|
+
|
39
|
+
... or like this:
|
40
|
+
|
41
|
+
class Post < ActiveRecord::Base
|
42
|
+
def self.per_page
|
43
|
+
50
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
... or don't worry about it at all. (WillPaginate defines it to be 30 if missing.)
|
48
|
+
You can also specify the count explicitly when calling +paginate+:
|
49
|
+
|
50
|
+
@posts = Post.paginate :page => params[:page], :per_page => 50
|
51
|
+
|
52
|
+
The +paginate+ finder wraps the original finder and returns your resultset that now has
|
53
|
+
some new properties. You can use the collection as you would with any ActiveRecord
|
54
|
+
resultset, but WillPaginate view helpers also need that object to be able to render pagination:
|
55
|
+
|
56
|
+
<ol>
|
57
|
+
<% for post in @posts -%>
|
58
|
+
<li>Render `post` in some nice way.</li>
|
59
|
+
<% end -%>
|
60
|
+
</ol>
|
61
|
+
|
62
|
+
<p>Now let's render us some pagination!</p>
|
63
|
+
<%= will_paginate @posts %>
|
64
|
+
|
65
|
+
|
66
|
+
== Authors, credits
|
67
|
+
|
68
|
+
Ruby port by: PJ Hyett, Mislav Marohnić (Sulien)
|
69
|
+
Contributors: K. Adam Christensen, Chris Wanstrath, Dr. Nic Williams
|
70
|
+
Original announcement: http://errtheblog.com/post/929
|
71
|
+
Original PHP source: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php
|
72
|
+
|
73
|
+
REPORT BUGS on Lighthouse: http://err.lighthouseapp.com/projects/466-plugins/overview
|
74
|
+
|
75
|
+
|
76
|
+
== Want Digg style?
|
77
|
+
|
78
|
+
Copy the following css into your stylesheet for a good start:
|
79
|
+
|
80
|
+
.pagination {
|
81
|
+
padding: 3px;
|
82
|
+
margin: 3px;
|
83
|
+
}
|
84
|
+
.pagination a {
|
85
|
+
padding: 2px 5px 2px 5px;
|
86
|
+
margin: 2px;
|
87
|
+
border: 1px solid #aaaadd;
|
88
|
+
text-decoration: none;
|
89
|
+
color: #000099;
|
90
|
+
}
|
91
|
+
.pagination a:hover, .pagination a:active {
|
92
|
+
border: 1px solid #000099;
|
93
|
+
color: #000;
|
94
|
+
}
|
95
|
+
.pagination span.current {
|
96
|
+
padding: 2px 5px 2px 5px;
|
97
|
+
margin: 2px;
|
98
|
+
border: 1px solid #000099;
|
99
|
+
font-weight: bold;
|
100
|
+
background-color: #000099;
|
101
|
+
color: #FFF;
|
102
|
+
}
|
103
|
+
.pagination span.disabled {
|
104
|
+
padding: 2px 5px 2px 5px;
|
105
|
+
margin: 2px;
|
106
|
+
border: 1px solid #eee;
|
107
|
+
color: #ddd;
|
108
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the will_paginate plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.pattern = 'test/**/*_test.rb'
|
11
|
+
t.verbose = true
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Generate RDoc documentation for the will_paginate plugin.'
|
15
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
16
|
+
files = ['README', 'LICENSE', 'lib/**/*.rb']
|
17
|
+
rdoc.rdoc_files.add(files)
|
18
|
+
rdoc.main = "README" # page to start on
|
19
|
+
rdoc.title = "will_paginate"
|
20
|
+
rdoc.template = File.exists?(t="/Users/chris/ruby/projects/err/rock/template.rb") ? t : "/var/www/rock/template.rb"
|
21
|
+
rdoc.rdoc_dir = 'doc' # rdoc output folder
|
22
|
+
rdoc.options << '--inline-source'
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'will_paginate/core_ext'
|
2
|
+
require 'will_paginate/collection'
|
3
|
+
require 'will_paginate/finder'
|
4
|
+
require 'will_paginate/view_helpers'
|
5
|
+
|
6
|
+
ActionView::Base.send :include, WillPaginate::ViewHelpers
|
7
|
+
ActiveRecord::Base.send :include, WillPaginate::Finder
|
8
|
+
|
9
|
+
module ActiveRecord::Associations
|
10
|
+
# to support paginating finders on associations, we have to mix in the
|
11
|
+
# method_missing magic from WillPaginate::Finder::ClassMethods to AssociationProxy
|
12
|
+
# subclasses, but in a different way for Rails 1.2.x and 2.0
|
13
|
+
(AssociationCollection.instance_methods.include?(:create!) ?
|
14
|
+
AssociationCollection : AssociationCollection.subclasses.map(&:constantize)
|
15
|
+
).push(HasManyThroughAssociation).each do |klass|
|
16
|
+
klass.class_eval do
|
17
|
+
include WillPaginate::Finder::ClassMethods
|
18
|
+
alias_method_chain :method_missing, :paginate
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module WillPaginate
|
2
|
+
# Arrays returned from paginating finds are, in fact, instances of this.
|
3
|
+
# You may think of WillPaginate::Collection as an ordinary array with some
|
4
|
+
# extra properties. Those properites are used by view helpers to generate
|
5
|
+
# correct page links.
|
6
|
+
#
|
7
|
+
class Collection < Array
|
8
|
+
attr_reader :current_page, :per_page
|
9
|
+
attr_accessor :total_entries
|
10
|
+
|
11
|
+
# These collection objects are instantiated by ActiveRecord paginating
|
12
|
+
# finders; there is no need to do it manually.
|
13
|
+
#
|
14
|
+
def initialize(page, per_page, total)
|
15
|
+
@current_page = page.to_i
|
16
|
+
@per_page = per_page.to_i
|
17
|
+
@total_entries = total.to_i
|
18
|
+
@total_pages = (@total_entries / @per_page.to_f).ceil
|
19
|
+
end
|
20
|
+
|
21
|
+
# The total number of pages.
|
22
|
+
def page_count
|
23
|
+
@total_pages
|
24
|
+
end
|
25
|
+
|
26
|
+
# Current offset of the paginated collection. If we're on the first page,
|
27
|
+
# it is always 0. If we're on the 2nd page and there are 30 entries per page,
|
28
|
+
# the offset is 30. This property is useful if you want to render ordinals
|
29
|
+
# besides your records: simply start with offset + 1.
|
30
|
+
#
|
31
|
+
def offset
|
32
|
+
(current_page - 1) * per_page
|
33
|
+
end
|
34
|
+
|
35
|
+
# current_page - 1 or nil if there is no previous page
|
36
|
+
def previous_page
|
37
|
+
current_page > 1 ? (current_page - 1) : nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# current_page + 1 or nil if there is no next page
|
41
|
+
def next_page
|
42
|
+
current_page < page_count ? (current_page + 1) : nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
unless Hash.instance_methods.include? 'except'
|
4
|
+
Hash.class_eval do
|
5
|
+
# Returns a new hash without the given keys.
|
6
|
+
def except(*keys)
|
7
|
+
rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
|
8
|
+
reject { |key,| rejected.include?(key) }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Replaces the hash without only the given keys.
|
12
|
+
def except!(*keys)
|
13
|
+
replace(except(*keys))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
unless Hash.instance_methods.include? 'slice'
|
19
|
+
Hash.class_eval do
|
20
|
+
# Returns a new hash with only the given keys.
|
21
|
+
def slice(*keys)
|
22
|
+
allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
|
23
|
+
reject { |key,| !allowed.include?(key) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Replaces the hash with only the given keys.
|
27
|
+
def slice!(*keys)
|
28
|
+
replace(slice(*keys))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
unless Array.instance_methods.include? 'paginate'
|
34
|
+
# http://www.desimcadam.com/archives/8
|
35
|
+
Array.class_eval do
|
36
|
+
def paginate(page = 1, per_page = 15)
|
37
|
+
pagination_array = WillPaginate::Collection.new(page, per_page, size)
|
38
|
+
start_index = pagination_array.offset
|
39
|
+
end_index = start_index + (per_page - 1)
|
40
|
+
array_to_concat = self[start_index..end_index]
|
41
|
+
array_to_concat.nil? ? [] : pagination_array.concat(array_to_concat)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module WillPaginate
|
2
|
+
# A mixin for ActiveRecord::Base. Provides `per_page` class method
|
3
|
+
# and makes `paginate` finders possible with some method_missing magic.
|
4
|
+
#
|
5
|
+
# Find out more in WillPaginate::Finder::ClassMethods
|
6
|
+
#
|
7
|
+
module Finder
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
class << base
|
11
|
+
alias_method_chain :method_missing, :paginate
|
12
|
+
define_method(:per_page) { 30 } unless respond_to?(:per_page)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# = Paginating finders for ActiveRecord models
|
17
|
+
#
|
18
|
+
# WillPaginate doesn't really add extra methods to your ActiveRecord models (except +per_page+
|
19
|
+
# unless it's already available). It simply intercepts
|
20
|
+
# the calls to paginating finders such as +paginate+, +paginate_by_user_id+ (and so on) and
|
21
|
+
# translates them to ordinary finders: +find+, +find_by_user_id+, etc. It does so with some
|
22
|
+
# method_missing magic, but you don't need to care for that. You simply use paginating finders
|
23
|
+
# same way you used ordinary ones. You only need to tell them what page you want in options.
|
24
|
+
#
|
25
|
+
# @topics = Topic.paginate :all, :page => params[:page]
|
26
|
+
#
|
27
|
+
# In paginating finders, "all" is implicit. No sense in paginating a single record, right? So:
|
28
|
+
#
|
29
|
+
# Post.paginate => Post.find :all
|
30
|
+
# Post.paginate_all_by_something => Post.find_all_by_something
|
31
|
+
# Post.paginate_by_something => Post.find_all_by_something
|
32
|
+
#
|
33
|
+
# Knowing that, the above example can be written simply as:
|
34
|
+
#
|
35
|
+
# @topics = Topic.paginate :page => params[:page]
|
36
|
+
#
|
37
|
+
# Don't forget to pass the +page+ parameter! Without it, paginating finders will raise an error.
|
38
|
+
#
|
39
|
+
# == Options
|
40
|
+
# Options for paginating finders are:
|
41
|
+
#
|
42
|
+
# page REQUIRED, but defaults to 1 if false or nil
|
43
|
+
# per_page (default is read from the model, which is 30 if not overriden)
|
44
|
+
# total entries not needed unless you want to count the records yourself somehow
|
45
|
+
# count hash of options that are used only for the call to count
|
46
|
+
#
|
47
|
+
module ClassMethods
|
48
|
+
# This methods wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string
|
49
|
+
# based on the params otherwise used by paginating finds: +page+ and +per_page+.
|
50
|
+
#
|
51
|
+
# Example:
|
52
|
+
#
|
53
|
+
# @developers = Developer.paginate_by_sql ['select * from developers where salary > ?', 80000],
|
54
|
+
# :page => params[:page], :per_page => 3
|
55
|
+
#
|
56
|
+
def paginate_by_sql(sql, options)
|
57
|
+
options, page, per_page = wp_parse_options!(options)
|
58
|
+
sanitized_query = sanitize_sql(sql)
|
59
|
+
total_entries = options[:total_entries] || count_by_sql("SELECT COUNT(*) FROM (#{sanitized_query}) AS count_table")
|
60
|
+
|
61
|
+
returning WillPaginate::Collection.new(page, per_page, total_entries) do |pager|
|
62
|
+
options.update :offset => pager.offset, :limit => pager.per_page
|
63
|
+
add_limit! sanitized_query, options
|
64
|
+
pager.replace find_by_sql(sanitized_query)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def respond_to?(method, include_priv = false)
|
69
|
+
case method.to_sym
|
70
|
+
when :paginate, :paginate_by_sql
|
71
|
+
true
|
72
|
+
else
|
73
|
+
super(method.to_s.sub(/^paginate/, 'find'), include_priv)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def method_missing_with_paginate(method, *args, &block)
|
80
|
+
# did somebody tried to paginate? if not, let them be
|
81
|
+
unless method.to_s.index('paginate') == 0
|
82
|
+
return method_missing_without_paginate(method, *args, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
options, page, per_page = wp_parse_options!(args.pop)
|
86
|
+
# paginate finders are really just find_* with limit and offset
|
87
|
+
finder = method.to_s.sub /^paginate/, 'find'
|
88
|
+
# magic counting for user convenience
|
89
|
+
total_entries = wp_count!(options, args, finder)
|
90
|
+
|
91
|
+
# :all is implicit
|
92
|
+
if finder == 'find'
|
93
|
+
args.unshift(:all) if args.empty?
|
94
|
+
elsif finder.index('find_by_') == 0
|
95
|
+
finder.sub! /^find/, 'find_all'
|
96
|
+
end
|
97
|
+
|
98
|
+
::Object.returning WillPaginate::Collection.new(page, per_page, total_entries) do |pager|
|
99
|
+
args << options.update(:offset => pager.offset, :limit => pager.per_page)
|
100
|
+
pager.replace send(finder, *args)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def wp_count!(options, args, finder)
|
105
|
+
# :total_entries and :count are mutually exclusive!
|
106
|
+
unless options[:total_entries]
|
107
|
+
unless args.first.is_a? Array
|
108
|
+
# count expects (almost) the same options as find
|
109
|
+
count_options = options.except :count, :order, :select
|
110
|
+
|
111
|
+
# merge the hash found in :count
|
112
|
+
# this allows you to specify :select, :order, or anything else just for the count query
|
113
|
+
count_options.update(options.delete(:count)) if options.key? :count
|
114
|
+
# extract the conditions from calls like "paginate_by_foo_and_bar"
|
115
|
+
conditions = wp_extract_finder_conditions(finder, args, count_options)
|
116
|
+
|
117
|
+
# scope_out adds a 'with_finder' method which acts like with_scope, if it's present
|
118
|
+
# then execute the count with the scoping provided by the with_finder
|
119
|
+
count = nil
|
120
|
+
counter = Proc.new { count = count(count_options) }
|
121
|
+
|
122
|
+
if respond_to?(scoper = finder.sub(/^find/, 'with'))
|
123
|
+
send(scoper, &counter)
|
124
|
+
else
|
125
|
+
with_scope(:find => { :conditions => conditions }, &counter)
|
126
|
+
end
|
127
|
+
|
128
|
+
count.respond_to?(:length) ? count.length : count
|
129
|
+
else
|
130
|
+
# array of IDs was passed, so its size is the total number
|
131
|
+
args.first.size
|
132
|
+
end
|
133
|
+
else
|
134
|
+
options.delete(:total_entries)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def wp_parse_options!(options)
|
139
|
+
raise ArgumentError, 'hash parameters expected' unless options.respond_to? :symbolize_keys!
|
140
|
+
options.symbolize_keys!
|
141
|
+
raise ArgumentError, ':page parameter required' unless options.key? :page
|
142
|
+
page = options.delete(:page) || 1
|
143
|
+
per_page = options.delete(:per_page) || self.per_page
|
144
|
+
[options, page, per_page]
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
# thanks to active record for making us duplicate this code
|
150
|
+
def wp_extract_finder_conditions(finder, arguments, count_options)
|
151
|
+
return unless match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(finder.to_s)
|
152
|
+
|
153
|
+
attribute_names = extract_attribute_names_from_match(match)
|
154
|
+
raise "I can't make sense of #{finder}" unless all_attributes_exists?(attribute_names)
|
155
|
+
construct_attributes_from_arguments(attribute_names, arguments)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|