From 6998b5f0f5fbbf47b1aad2a6c0293766a720e616 Mon Sep 17 00:00:00 2001 From: Grant Hutchins & Sam Obukwelu Date: Fri, 20 May 2011 18:17:28 -0400 Subject: [PATCH] Active Record models that were subclassed before Kaminari::ActiveRecordExtension is included pick up the extensions. --- .../models/active_record_extension.rb | 20 +- .../models/active_record_model_extension.rb | 20 ++ spec/fake_app.rb | 1 + spec/fake_gem.rb | 6 + spec/models/scopes_spec.rb | 288 +++++++++--------- spec/spec_helper.rb | 1 + 6 files changed, 181 insertions(+), 155 deletions(-) create mode 100644 lib/kaminari/models/active_record_model_extension.rb create mode 100644 spec/fake_gem.rb diff --git a/lib/kaminari/models/active_record_extension.rb b/lib/kaminari/models/active_record_extension.rb index a414aee..6367ef3 100644 --- a/lib/kaminari/models/active_record_extension.rb +++ b/lib/kaminari/models/active_record_extension.rb @@ -1,24 +1,18 @@ -require File.join(File.dirname(__FILE__), 'active_record_relation_methods') +require File.join(File.dirname(__FILE__), 'active_record_model_extension') module Kaminari module ActiveRecordExtension extend ActiveSupport::Concern included do + # Future subclasses will pick up the model extension def self.inherited(kls) #:nodoc: super + kls.send(:include, Kaminari::ActiveRecordModelExtension) + end - kls.class_eval do - include Kaminari::ConfigurationMethods - - # Fetch the values at the specified page number - # Model.page(5) - scope :page, Proc.new {|num| - limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1)) - } do - include Kaminari::ActiveRecordRelationMethods - include Kaminari::PageScopeMethods - end - end + # Existing subclasses pick up the model extension as well + self.descendants.each do |kls| + kls.send(:include, Kaminari::ActiveRecordModelExtension) end end end diff --git a/lib/kaminari/models/active_record_model_extension.rb b/lib/kaminari/models/active_record_model_extension.rb new file mode 100644 index 0000000..963b74e --- /dev/null +++ b/lib/kaminari/models/active_record_model_extension.rb @@ -0,0 +1,20 @@ +require File.join(File.dirname(__FILE__), 'active_record_relation_methods') + +module Kaminari + module ActiveRecordModelExtension + extend ActiveSupport::Concern + + included do + self.send(:include, Kaminari::ConfigurationMethods) + + # Fetch the values at the specified page number + # Model.page(5) + self.scope :page, Proc.new {|num| + limit(default_per_page).offset(default_per_page * ([num.to_i, 1].max - 1)) + } do + include Kaminari::ActiveRecordRelationMethods + include Kaminari::PageScopeMethods + end + end + end +end diff --git a/spec/fake_app.rb b/spec/fake_app.rb index 2e57e5b..ed77345 100644 --- a/spec/fake_app.rb +++ b/spec/fake_app.rb @@ -72,6 +72,7 @@ Object.const_set(:ApplicationHelper, Module.new) #migrations class CreateAllTables < ActiveRecord::Migration def self.up + create_table(:gem_defined_models) { |t| t.string :name; t.integer :age } create_table(:users) {|t| t.string :name; t.integer :age} create_table(:books) {|t| t.string :title} create_table(:readerships) {|t| t.integer :user_id; t.integer :book_id } diff --git a/spec/fake_gem.rb b/spec/fake_gem.rb new file mode 100644 index 0000000..a142811 --- /dev/null +++ b/spec/fake_gem.rb @@ -0,0 +1,6 @@ +# Simulate a gem providing a subclass of ActiveRecord::Base before the Railtie is loaded. + +require 'active_record' + +class GemDefinedModel < ActiveRecord::Base +end diff --git a/spec/models/scopes_spec.rb b/spec/models/scopes_spec.rb index 4da064c..8678e65 100644 --- a/spec/models/scopes_spec.rb +++ b/spec/models/scopes_spec.rb @@ -1,149 +1,153 @@ require File.expand_path('../spec_helper', File.dirname(__FILE__)) +shared_examples_for 'the first page' do + it { should have(25).users } + its('first.name') { should == 'user001' } +end + +shared_examples_for 'blank page' do + it { should have(0).users } +end + describe Kaminari::ActiveRecordExtension do - before :all do - 1.upto(100) {|i| User.create! :name => "user#{'%03d' % i}", :age => (i / 10)} - end + [User, GemDefinedModel].each do |model_class| + context "for #{model_class}" do + before :all do + 1.upto(100) {|i| model_class.create! :name => "user#{'%03d' % i}", :age => (i / 10)} + end - describe '#page' do - shared_examples_for 'the first page' do - it { should have(25).users } - its('first.name') { should == 'user001' } + describe '#page' do + context 'page 1' do + subject { model_class.page 1 } + it_should_behave_like 'the first page' + end + + context 'page 2' do + subject { model_class.page 2 } + it { should have(25).users } + its('first.name') { should == 'user026' } + end + + context 'page without an argument' do + subject { model_class.page } + it_should_behave_like 'the first page' + end + + context 'page < 1' do + subject { model_class.page 0 } + it_should_behave_like 'the first page' + end + + context 'page > max page' do + subject { model_class.page 5 } + it_should_behave_like 'blank page' + end + + describe 'ensure #order_values is preserved' do + subject { model_class.order('id').page 1 } + its(:order_values) { should == ['id'] } + end + end + + describe '#per' do + context 'page 1 per 5' do + subject { model_class.page(1).per(5) } + it { should have(5).users } + its('first.name') { should == 'user001' } + end + end + + describe '#num_pages' do + context 'per 25 (default)' do + subject { model_class.page } + its(:num_pages) { should == 4 } + end + + context 'per 7' do + subject { model_class.page(2).per(7) } + its(:num_pages) { should == 15 } + end + + context 'per 65536' do + subject { model_class.page(50).per(65536) } + its(:num_pages) { should == 1 } + end + + context 'per 0 (using default)' do + subject { model_class.page(50).per(0) } + its(:num_pages) { should == 4 } + end + + context 'per -1 (using default)' do + subject { model_class.page(5).per(-1) } + its(:num_pages) { should == 4 } + end + + context 'per "String value that can not be converted into Number" (using default)' do + subject { model_class.page(5).per('aho') } + its(:num_pages) { should == 4 } + end + end + + describe '#current_page' do + context 'page 1' do + subject { model_class.page } + its(:current_page) { should == 1 } + end + + context 'page 2' do + subject { model_class.page(2).per 3 } + its(:current_page) { should == 2 } + end + end + + describe '#first_page?' do + context 'on first page' do + subject { model_class.page(1).per(10) } + its(:first_page?) { should == true } + end + + context 'not on first page' do + subject { model_class.page(5).per(10) } + its(:first_page?) { should == false } + end + end + + describe '#last_page?' do + context 'on last page' do + subject { model_class.page(10).per(10) } + its(:last_page?) { should == true } + end + + context 'not on last page' do + subject { model_class.page(1).per(10) } + its(:last_page?) { should == false } + end + end + + describe '#count' do + context 'page 1' do + subject { model_class.page } + its(:count) { should == 25 } + end + + context 'page 2' do + subject { model_class.page 2 } + its(:count) { should == 25 } + end + end + + context 'chained with .group' do + subject { model_class.group('age').page(2).per 5 } + # 0..10 + its(:total_count) { should == 11 } + its(:num_pages) { should == 3 } + end + + context 'activerecord descendants' do + subject { ActiveRecord::Base.descendants } + its(:length) { should_not == 0 } + end end - - shared_examples_for 'blank page' do - it { should have(0).users } - end - - context 'page 1' do - subject { User.page 1 } - it_should_behave_like 'the first page' - end - - context 'page 2' do - subject { User.page 2 } - it { should have(25).users } - its('first.name') { should == 'user026' } - end - - context 'page without an argument' do - subject { User.page } - it_should_behave_like 'the first page' - end - - context 'page < 1' do - subject { User.page 0 } - it_should_behave_like 'the first page' - end - - context 'page > max page' do - subject { User.page 5 } - it_should_behave_like 'blank page' - end - - describe 'ensure #order_values is preserved' do - subject { User.order('id').page 1 } - its(:order_values) { should == ['id'] } - end - end - - describe '#per' do - context 'page 1 per 5' do - subject { User.page(1).per(5) } - it { should have(5).users } - its('first.name') { should == 'user001' } - end - end - - describe '#num_pages' do - context 'per 25 (default)' do - subject { User.page } - its(:num_pages) { should == 4 } - end - - context 'per 7' do - subject { User.page(2).per(7) } - its(:num_pages) { should == 15 } - end - - context 'per 65536' do - subject { User.page(50).per(65536) } - its(:num_pages) { should == 1 } - end - - context 'per 0 (using default)' do - subject { User.page(50).per(0) } - its(:num_pages) { should == 4 } - end - - context 'per -1 (using default)' do - subject { User.page(5).per(-1) } - its(:num_pages) { should == 4 } - end - - context 'per "String value that can not be converted into Number" (using default)' do - subject { User.page(5).per('aho') } - its(:num_pages) { should == 4 } - end - end - - describe '#current_page' do - context 'page 1' do - subject { User.page } - its(:current_page) { should == 1 } - end - - context 'page 2' do - subject { User.page(2).per 3 } - its(:current_page) { should == 2 } - end - end - - describe '#first_page?' do - context 'on first page' do - subject { User.page(1).per(10) } - its(:first_page?) { should == true } - end - - context 'not on first page' do - subject { User.page(5).per(10) } - its(:first_page?) { should == false } - end - end - - describe '#last_page?' do - context 'on last page' do - subject { User.page(10).per(10) } - its(:last_page?) { should == true } - end - - context 'not on last page' do - subject { User.page(1).per(10) } - its(:last_page?) { should == false } - end - end - - describe '#count' do - context 'page 1' do - subject { User.page } - its(:count) { should == 25 } - end - - context 'page 2' do - subject { User.page 2 } - its(:count) { should == 25 } - end - end - - context 'chained with .group' do - subject { User.group('age').page(2).per 5 } - # 0..10 - its(:total_count) { should == 11 } - its(:num_pages) { should == 3 } - end - - context 'activerecord descendants' do - subject { ActiveRecord::Base.descendants } - its(:length) { should_not == 0 } end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 41d5cff..7715c81 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,6 +12,7 @@ require 'database_cleaner' if RUBY_VERSION >= '1.9.2' YAML::ENGINE.yamler = 'syck' end +require File.join(File.dirname(__FILE__), 'fake_gem') require File.join(File.dirname(__FILE__), 'fake_app') require 'rspec/rails'