Skip to content
This repository

ActiveRecord::Base subclasses that are defined before Kaminari is loaded now get the proper mixins #119

Merged
merged 1 commit into from over 2 years ago

4 participants

Pivotal Casebook J. Pablo Fernández 2-718 Akira Matsuda
Pivotal Casebook

We have a gem that provides an ActiveRecord::Base subclass. However, since it is loaded by Bundler before the self.included hook is mixed into to ActiveRecord::Base, it never gets the "page" scope.

With our fix, mixing in the module will back-fill existing subclasses with the scope.

Active Record models that were subclassed before Kaminari::ActiveReco…
…rdExtension is included pick up the extensions.
6998b5f
J. Pablo Fernández
pupeno commented May 27, 2011

I also had the problem of not having pagination of these model, in my case it was the Audit model. I switched to Casecommons's repo and it worked :)

2-718
2-718 commented May 30, 2011

I'm using the acts_as_audited gem v2.0.0.rc7 and the Audit class would not paginate until I switched to Casecommon's kaminari v0.12.4 repo. This works for me now.

Akira Matsuda amatsuda merged commit 6998b5f into from August 21, 2011
Akira Matsuda amatsuda closed this August 21, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

May 20, 2011
Active Record models that were subclassed before Kaminari::ActiveReco…
…rdExtension is included pick up the extensions.
6998b5f
This page is out of date. Refresh to see the latest.
20  lib/kaminari/models/active_record_extension.rb
... ...
@@ -1,24 +1,18 @@
1  
-require File.join(File.dirname(__FILE__), 'active_record_relation_methods')
  1
+require File.join(File.dirname(__FILE__), 'active_record_model_extension')
2 2
 
3 3
 module Kaminari
4 4
   module ActiveRecordExtension
5 5
     extend ActiveSupport::Concern
6 6
     included do
  7
+      # Future subclasses will pick up the model extension
7 8
       def self.inherited(kls) #:nodoc:
8 9
         super
  10
+        kls.send(:include, Kaminari::ActiveRecordModelExtension)
  11
+      end
9 12
 
10  
-        kls.class_eval do
11  
-          include Kaminari::ConfigurationMethods
12  
-
13  
-          # Fetch the values at the specified page number
14  
-          #   Model.page(5)
15  
-          scope :page, Proc.new {|num|
16  
-            limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1))
17  
-          } do
18  
-            include Kaminari::ActiveRecordRelationMethods
19  
-            include Kaminari::PageScopeMethods
20  
-          end
21  
-        end
  13
+      # Existing subclasses pick up the model extension as well
  14
+      self.descendants.each do |kls|
  15
+        kls.send(:include, Kaminari::ActiveRecordModelExtension)
22 16
       end
23 17
     end
24 18
   end
20  lib/kaminari/models/active_record_model_extension.rb
... ...
@@ -0,0 +1,20 @@
  1
+require File.join(File.dirname(__FILE__), 'active_record_relation_methods')
  2
+
  3
+module Kaminari
  4
+  module ActiveRecordModelExtension
  5
+    extend ActiveSupport::Concern
  6
+
  7
+    included do
  8
+      self.send(:include, Kaminari::ConfigurationMethods)
  9
+
  10
+      # Fetch the values at the specified page number
  11
+      #   Model.page(5)
  12
+      self.scope :page, Proc.new {|num|
  13
+        limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1))
  14
+      } do
  15
+        include Kaminari::ActiveRecordRelationMethods
  16
+        include Kaminari::PageScopeMethods
  17
+      end
  18
+    end
  19
+  end
  20
+end
1  spec/fake_app.rb
@@ -72,6 +72,7 @@ def index
72 72
 #migrations
73 73
 class CreateAllTables < ActiveRecord::Migration
74 74
   def self.up
  75
+    create_table(:gem_defined_models) { |t| t.string :name; t.integer :age }
75 76
     create_table(:users) {|t| t.string :name; t.integer :age}
76 77
     create_table(:books) {|t| t.string :title}
77 78
     create_table(:readerships) {|t| t.integer :user_id; t.integer :book_id }
6  spec/fake_gem.rb
... ...
@@ -0,0 +1,6 @@
  1
+# Simulate a gem providing a subclass of ActiveRecord::Base before the Railtie is loaded.
  2
+
  3
+require 'active_record'
  4
+
  5
+class GemDefinedModel < ActiveRecord::Base
  6
+end
288  spec/models/scopes_spec.rb
... ...
@@ -1,149 +1,153 @@
1 1
 require File.expand_path('../spec_helper', File.dirname(__FILE__))
2 2
 
3  
-describe Kaminari::ActiveRecordExtension do
4  
-  before :all do
5  
-    1.upto(100) {|i| User.create! :name => "user#{'%03d' % i}", :age => (i / 10)}
6  
-  end
7  
-
8  
-  describe '#page' do
9  
-    shared_examples_for 'the first page' do
10  
-      it { should have(25).users }
11  
-      its('first.name') { should == 'user001' }
12  
-    end
13  
-
14  
-    shared_examples_for 'blank page' do
15  
-      it { should have(0).users }
16  
-    end
17  
-
18  
-    context 'page 1' do
19  
-      subject { User.page 1 }
20  
-      it_should_behave_like 'the first page'
21  
-    end
22  
-
23  
-    context 'page 2' do
24  
-      subject { User.page 2 }
25  
-      it { should have(25).users }
26  
-      its('first.name') { should == 'user026' }
27  
-    end
28  
-
29  
-    context 'page without an argument' do
30  
-      subject { User.page }
31  
-      it_should_behave_like 'the first page'
32  
-    end
33  
-
34  
-    context 'page < 1' do
35  
-      subject { User.page 0 }
36  
-      it_should_behave_like 'the first page'
37  
-    end
38  
-
39  
-    context 'page > max page' do
40  
-      subject { User.page 5 }
41  
-      it_should_behave_like 'blank page'
42  
-    end
43  
-
44  
-    describe 'ensure #order_values is preserved' do
45  
-      subject { User.order('id').page 1 }
46  
-      its(:order_values) { should == ['id'] }
47  
-    end
48  
-  end
49  
-
50  
-  describe '#per' do
51  
-    context 'page 1 per 5' do
52  
-      subject { User.page(1).per(5) }
53  
-      it { should have(5).users }
54  
-      its('first.name') { should == 'user001' }
55  
-    end
56  
-  end
57  
-
58  
-  describe '#num_pages' do
59  
-    context 'per 25 (default)' do
60  
-      subject { User.page }
61  
-      its(:num_pages) { should == 4 }
62  
-    end
63  
-
64  
-    context 'per 7' do
65  
-      subject { User.page(2).per(7) }
66  
-      its(:num_pages) { should == 15 }
67  
-    end
68  
-
69  
-    context 'per 65536' do
70  
-      subject { User.page(50).per(65536) }
71  
-      its(:num_pages) { should == 1 }
72  
-    end
73  
-
74  
-    context 'per 0 (using default)' do
75  
-      subject { User.page(50).per(0) }
76  
-      its(:num_pages) { should == 4 }
77  
-    end
78  
-
79  
-    context 'per -1 (using default)' do
80  
-      subject { User.page(5).per(-1) }
81  
-      its(:num_pages) { should == 4 }
82  
-    end
83  
-
84  
-    context 'per "String value that can not be converted into Number" (using default)' do
85  
-      subject { User.page(5).per('aho') }
86  
-      its(:num_pages) { should == 4 }
87  
-    end
88  
-  end
89  
-
90  
-  describe '#current_page' do
91  
-    context 'page 1' do
92  
-      subject { User.page }
93  
-      its(:current_page) { should == 1 }
94  
-    end
95  
-
96  
-    context 'page 2' do
97  
-      subject { User.page(2).per 3 }
98  
-      its(:current_page) { should == 2 }
99  
-    end
100  
-  end
101  
-
102  
-  describe '#first_page?' do
103  
-    context 'on first page' do
104  
-      subject { User.page(1).per(10) }
105  
-      its(:first_page?) { should == true }
106  
-    end
107  
-
108  
-    context 'not on first page' do
109  
-      subject { User.page(5).per(10) }
110  
-      its(:first_page?) { should == false }
111  
-    end
112  
-  end
113  
-
114  
-  describe '#last_page?' do
115  
-    context 'on last page' do
116  
-      subject { User.page(10).per(10) }
117  
-      its(:last_page?) { should == true }
118  
-    end
119  
-
120  
-    context 'not on last page' do
121  
-      subject { User.page(1).per(10) }
122  
-      its(:last_page?) { should == false }
123  
-    end
124  
-  end
  3
+shared_examples_for 'the first page' do
  4
+  it { should have(25).users }
  5
+  its('first.name') { should == 'user001' }
  6
+end
125 7
 
126  
-  describe '#count' do
127  
-    context 'page 1' do
128  
-      subject { User.page }
129  
-      its(:count) { should == 25 }
130  
-    end
  8
+shared_examples_for 'blank page' do
  9
+  it { should have(0).users }
  10
+end
131 11
 
132  
-    context 'page 2' do
133  
-      subject { User.page 2 }
134  
-      its(:count) { should == 25 }
  12
+describe Kaminari::ActiveRecordExtension do
  13
+  [User, GemDefinedModel].each do |model_class|
  14
+    context "for #{model_class}" do
  15
+      before :all do
  16
+        1.upto(100) {|i| model_class.create! :name => "user#{'%03d' % i}", :age => (i / 10)}
  17
+      end
  18
+
  19
+      describe '#page' do
  20
+        context 'page 1' do
  21
+          subject { model_class.page 1 }
  22
+          it_should_behave_like 'the first page'
  23
+        end
  24
+
  25
+        context 'page 2' do
  26
+          subject { model_class.page 2 }
  27
+          it { should have(25).users }
  28
+          its('first.name') { should == 'user026' }
  29
+        end
  30
+
  31
+        context 'page without an argument' do
  32
+          subject { model_class.page }
  33
+          it_should_behave_like 'the first page'
  34
+        end
  35
+
  36
+        context 'page < 1' do
  37
+          subject { model_class.page 0 }
  38
+          it_should_behave_like 'the first page'
  39
+        end
  40
+
  41
+        context 'page > max page' do
  42
+          subject { model_class.page 5 }
  43
+          it_should_behave_like 'blank page'
  44
+        end
  45
+
  46
+        describe 'ensure #order_values is preserved' do
  47
+          subject { model_class.order('id').page 1 }
  48
+          its(:order_values) { should == ['id'] }
  49
+        end
  50
+      end
  51
+
  52
+      describe '#per' do
  53
+        context 'page 1 per 5' do
  54
+          subject { model_class.page(1).per(5) }
  55
+          it { should have(5).users }
  56
+          its('first.name') { should == 'user001' }
  57
+        end
  58
+      end
  59
+
  60
+      describe '#num_pages' do
  61
+        context 'per 25 (default)' do
  62
+          subject { model_class.page }
  63
+          its(:num_pages) { should == 4 }
  64
+        end
  65
+
  66
+        context 'per 7' do
  67
+          subject { model_class.page(2).per(7) }
  68
+          its(:num_pages) { should == 15 }
  69
+        end
  70
+
  71
+        context 'per 65536' do
  72
+          subject { model_class.page(50).per(65536) }
  73
+          its(:num_pages) { should == 1 }
  74
+        end
  75
+
  76
+        context 'per 0 (using default)' do
  77
+          subject { model_class.page(50).per(0) }
  78
+          its(:num_pages) { should == 4 }
  79
+        end
  80
+
  81
+        context 'per -1 (using default)' do
  82
+          subject { model_class.page(5).per(-1) }
  83
+          its(:num_pages) { should == 4 }
  84
+        end
  85
+
  86
+        context 'per "String value that can not be converted into Number" (using default)' do
  87
+          subject { model_class.page(5).per('aho') }
  88
+          its(:num_pages) { should == 4 }
  89
+        end
  90
+      end
  91
+
  92
+      describe '#current_page' do
  93
+        context 'page 1' do
  94
+          subject { model_class.page }
  95
+          its(:current_page) { should == 1 }
  96
+        end
  97
+
  98
+        context 'page 2' do
  99
+          subject { model_class.page(2).per 3 }
  100
+          its(:current_page) { should == 2 }
  101
+        end
  102
+      end
  103
+
  104
+      describe '#first_page?' do
  105
+        context 'on first page' do
  106
+          subject { model_class.page(1).per(10) }
  107
+          its(:first_page?) { should == true }
  108
+        end
  109
+
  110
+        context 'not on first page' do
  111
+          subject { model_class.page(5).per(10) }
  112
+          its(:first_page?) { should == false }
  113
+        end
  114
+      end
  115
+
  116
+      describe '#last_page?' do
  117
+        context 'on last page' do
  118
+          subject { model_class.page(10).per(10) }
  119
+          its(:last_page?) { should == true }
  120
+        end
  121
+
  122
+        context 'not on last page' do
  123
+          subject { model_class.page(1).per(10) }
  124
+          its(:last_page?) { should == false }
  125
+        end
  126
+      end
  127
+
  128
+      describe '#count' do
  129
+        context 'page 1' do
  130
+          subject { model_class.page }
  131
+          its(:count) { should == 25 }
  132
+        end
  133
+
  134
+        context 'page 2' do
  135
+          subject { model_class.page 2 }
  136
+          its(:count) { should == 25 }
  137
+        end
  138
+      end
  139
+
  140
+      context 'chained with .group' do
  141
+        subject { model_class.group('age').page(2).per 5 }
  142
+        # 0..10
  143
+        its(:total_count) { should == 11 }
  144
+        its(:num_pages) { should == 3 }
  145
+      end
  146
+
  147
+      context 'activerecord descendants' do
  148
+        subject { ActiveRecord::Base.descendants }
  149
+        its(:length) { should_not == 0 }
  150
+      end
135 151
     end
136 152
   end
137  
-
138  
-  context 'chained with .group' do
139  
-    subject { User.group('age').page(2).per 5 }
140  
-    # 0..10
141  
-    its(:total_count) { should == 11 }
142  
-    its(:num_pages) { should == 3 }
143  
-  end
144  
-
145  
-  context 'activerecord descendants' do
146  
-    subject { ActiveRecord::Base.descendants }
147  
-    its(:length) { should_not == 0 }
148  
-  end
149 153
 end
1  spec/spec_helper.rb
@@ -12,6 +12,7 @@
12 12
 if RUBY_VERSION >= '1.9.2'
13 13
   YAML::ENGINE.yamler = 'syck'
14 14
 end
  15
+require File.join(File.dirname(__FILE__), 'fake_gem')
15 16
 require File.join(File.dirname(__FILE__), 'fake_app')
16 17
 
17 18
 require 'rspec/rails'
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.