ranked-model 0.4.0 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.travis.yml +43 -74
- data/Appraisals +72 -0
- data/Gemfile +7 -23
- data/Readme.mkd +139 -19
- data/gemfiles/rails_4_2.gemfile +23 -0
- data/gemfiles/rails_5_0.gemfile +22 -0
- data/gemfiles/rails_5_1.gemfile +22 -0
- data/gemfiles/rails_5_2.gemfile +22 -0
- data/gemfiles/rails_6_0.gemfile +22 -0
- data/lib/ranked-model.rb +20 -5
- data/lib/ranked-model/ranker.rb +91 -70
- data/lib/ranked-model/version.rb +1 -1
- data/ranked-model.gemspec +9 -8
- data/spec/duck-model/column_default_ducks_spec.rb +29 -0
- data/spec/duck-model/duck_spec.rb +207 -78
- data/spec/duck-model/lots_of_ducks_spec.rb +50 -38
- data/spec/duck-model/wrong_ducks_spec.rb +11 -0
- data/spec/ego-model/ego_spec.rb +3 -3
- data/spec/number-model/number_spec.rb +39 -0
- data/spec/player-model/records_already_exist_spec.rb +1 -1
- data/spec/ranked-model/ranker_spec.rb +18 -0
- data/spec/ranked-model/version_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -0
- data/spec/sti-model/element_spec.rb +24 -24
- data/spec/sti-model/vehicle_spec.rb +6 -6
- data/spec/support/active_record.rb +28 -5
- data/spec/support/database.yml +9 -17
- metadata +67 -44
@@ -5,17 +5,31 @@ describe Duck do
|
|
5
5
|
before {
|
6
6
|
200.times do |i|
|
7
7
|
Duck.create \
|
8
|
-
:name => "Duck #{i}"
|
8
|
+
:name => "Duck #{i + 1}"
|
9
9
|
end
|
10
10
|
}
|
11
11
|
|
12
|
+
describe "a large number of records" do
|
13
|
+
before { @ducks = Duck.all }
|
14
|
+
|
15
|
+
describe "the last two ducks' rows' difference" do
|
16
|
+
subject { @ducks[-1].row - @ducks[-2].row }
|
17
|
+
it { is_expected.not_to be_between(-1, 1) }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "the second to last two ducks' rows' difference" do
|
21
|
+
subject { @ducks[-2].row - @ducks[-3].row }
|
22
|
+
it { is_expected.not_to be_between(-1, 1) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
12
26
|
describe "setting and fetching by position" do
|
13
27
|
|
14
28
|
describe '137' do
|
15
29
|
|
16
30
|
before {
|
17
31
|
@last = Duck.last
|
18
|
-
@last.
|
32
|
+
@last.update :row_position => 137
|
19
33
|
}
|
20
34
|
|
21
35
|
subject { Duck.ranker(:row).with(Duck.new).current_at_position(137).instance }
|
@@ -28,7 +42,7 @@ describe Duck do
|
|
28
42
|
|
29
43
|
before {
|
30
44
|
@last = Duck.last
|
31
|
-
@last.
|
45
|
+
@last.update :row_position => 2
|
32
46
|
}
|
33
47
|
|
34
48
|
subject { Duck.ranker(:row).with(Duck.new).current_at_position(2).instance }
|
@@ -41,7 +55,7 @@ describe Duck do
|
|
41
55
|
|
42
56
|
before {
|
43
57
|
@last = Duck.last
|
44
|
-
@last.
|
58
|
+
@last.update :row_position => :last
|
45
59
|
}
|
46
60
|
|
47
61
|
subject { Duck.rank(:row).last }
|
@@ -54,7 +68,7 @@ describe Duck do
|
|
54
68
|
|
55
69
|
before {
|
56
70
|
@last = Duck.last
|
57
|
-
@last.
|
71
|
+
@last.update :row_position => :first
|
58
72
|
}
|
59
73
|
|
60
74
|
subject { Duck.rank(:row).first }
|
@@ -73,15 +87,15 @@ describe Duck do
|
|
73
87
|
@first = Duck.first
|
74
88
|
@second = Duck.offset(1).first
|
75
89
|
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
|
76
|
-
@first.
|
77
|
-
@second.
|
90
|
+
@first.update :row => RankedModel::MAX_RANK_VALUE
|
91
|
+
@second.update :row => RankedModel::MAX_RANK_VALUE
|
78
92
|
}
|
79
93
|
|
80
94
|
context {
|
81
95
|
|
82
96
|
subject { Duck.rank(:row).collect {|d| d.id } }
|
83
97
|
|
84
|
-
it {
|
98
|
+
it { is_expected.to eq(@ordered[0..-2] + [@ordered[-1], @first.id, @second.id]) }
|
85
99
|
|
86
100
|
}
|
87
101
|
|
@@ -91,24 +105,24 @@ describe Duck do
|
|
91
105
|
|
92
106
|
before {
|
93
107
|
Duck.first(50).each_with_index do |d, index|
|
94
|
-
d.
|
108
|
+
d.update :age => index % 10, :pond => "Pond #{index / 10}"
|
95
109
|
end
|
96
|
-
@duck_11 = Duck.
|
97
|
-
@duck_12 = Duck.
|
110
|
+
@duck_11 = Duck.where(:pond => 'Pond 1').rank(:age).first
|
111
|
+
@duck_12 = Duck.where(:pond => 'Pond 1').rank(:age).second
|
98
112
|
@ordered = Duck.where(:pond => 'Pond 1').rank(:age).where(Duck.arel_table[:id].not_in([@duck_11.id, @duck_12.id])).collect {|d| d.id }
|
99
|
-
@duck_11.
|
100
|
-
@duck_12.
|
113
|
+
@duck_11.update :age => RankedModel::MAX_RANK_VALUE
|
114
|
+
@duck_12.update :age => RankedModel::MAX_RANK_VALUE
|
101
115
|
}
|
102
116
|
|
103
117
|
context {
|
104
118
|
subject { Duck.where(:pond => 'Pond 1').rank(:age).collect {|d| d.id } }
|
105
119
|
|
106
|
-
it {
|
120
|
+
it { is_expected.to eq(@ordered[0..-2] + [@ordered[-1], @duck_11.id, @duck_12.id]) }
|
107
121
|
}
|
108
122
|
|
109
123
|
context {
|
110
124
|
subject { Duck.first.age }
|
111
|
-
it {
|
125
|
+
it { is_expected.to eq(0)}
|
112
126
|
}
|
113
127
|
|
114
128
|
end
|
@@ -119,15 +133,15 @@ describe Duck do
|
|
119
133
|
@first = Duck.first
|
120
134
|
@second = Duck.offset(1).first
|
121
135
|
@ordered = Duck.rank(:row).where(Duck.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
|
122
|
-
@first.
|
123
|
-
@second.
|
136
|
+
@first.update :row => RankedModel::MIN_RANK_VALUE
|
137
|
+
@second.update :row => RankedModel::MIN_RANK_VALUE
|
124
138
|
}
|
125
139
|
|
126
140
|
context {
|
127
141
|
|
128
142
|
subject { Duck.rank(:row).collect {|d| d.id } }
|
129
143
|
|
130
|
-
it {
|
144
|
+
it { is_expected.to eq([@second.id, @first.id] + @ordered) }
|
131
145
|
|
132
146
|
}
|
133
147
|
|
@@ -135,32 +149,30 @@ describe Duck do
|
|
135
149
|
|
136
150
|
describe "with no more gaps" do
|
137
151
|
|
138
|
-
before
|
139
|
-
@first = Duck.first
|
140
|
-
@second = Duck.
|
141
|
-
@third = Duck.offset(2).first
|
142
|
-
@fourth = Duck.offset(
|
152
|
+
before do
|
153
|
+
@first = Duck.rank(:row).first
|
154
|
+
@second = Duck.rank(:row).offset(1).first
|
155
|
+
@third = Duck.rank(:row).offset(2).first
|
156
|
+
@fourth = Duck.rank(:row).offset(3).first
|
143
157
|
@lower = Duck.rank(:row).
|
144
158
|
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
145
159
|
where(Duck.arel_table[:row].lt(RankedModel::MAX_RANK_VALUE / 2)).
|
146
|
-
|
160
|
+
pluck(:id)
|
147
161
|
@upper = Duck.rank(:row).
|
148
162
|
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
149
163
|
where(Duck.arel_table[:row].gteq(RankedModel::MAX_RANK_VALUE / 2)).
|
150
|
-
|
151
|
-
@first.
|
152
|
-
@second.
|
153
|
-
@third.
|
154
|
-
@fourth.
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
}
|
164
|
+
pluck(:id)
|
165
|
+
@first.update(row: RankedModel::MIN_RANK_VALUE)
|
166
|
+
@second.update(row: RankedModel::MAX_RANK_VALUE)
|
167
|
+
@third.update(row: (RankedModel::MAX_RANK_VALUE / 2))
|
168
|
+
@fourth.update(row: @third.row)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'works correctly' do
|
172
|
+
result = Duck.rank(:row).pluck(:id)
|
173
|
+
expected = [@first.id, *@lower, @fourth.id, @third.id, *@upper, @second.id]
|
174
|
+
expect(result).to eq(expected)
|
175
|
+
end
|
164
176
|
|
165
177
|
end
|
166
178
|
|
@@ -23,3 +23,14 @@ describe WrongFieldDuck do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
end
|
26
|
+
|
27
|
+
describe ReallyWrongFieldDuck do
|
28
|
+
|
29
|
+
it "should raise an error because of a specific unknown field" do
|
30
|
+
|
31
|
+
expect {
|
32
|
+
ReallyWrongFieldDuck.create(:name => 'Quicky', :pond => 'Shin')
|
33
|
+
}.to raise_error(RankedModel::InvalidField, 'No field called "non_existant_field" found in model')
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/spec/ego-model/ego_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe Ego do
|
|
10
10
|
}
|
11
11
|
@egos.each { |name, ego|
|
12
12
|
ego.reload
|
13
|
-
ego.
|
13
|
+
ego.update :size_position => 0
|
14
14
|
ego.save!
|
15
15
|
}
|
16
16
|
@egos.each {|name, ego| ego.reload }
|
@@ -19,8 +19,8 @@ describe Ego do
|
|
19
19
|
describe "sorting on size alternative primary key" do
|
20
20
|
|
21
21
|
before {
|
22
|
-
@egos[:nick].
|
23
|
-
@egos[:sally].
|
22
|
+
@egos[:nick].update :size_position => 0
|
23
|
+
@egos[:sally].update :size_position => 2
|
24
24
|
}
|
25
25
|
|
26
26
|
subject { Ego.rank(:size).to_a }
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Number do
|
4
|
+
|
5
|
+
before {
|
6
|
+
200.times do |i|
|
7
|
+
Number.create :value => i
|
8
|
+
end
|
9
|
+
}
|
10
|
+
|
11
|
+
describe "a rearrangement with keyword column name" do
|
12
|
+
|
13
|
+
before {
|
14
|
+
@first = Number.first
|
15
|
+
@second = Number.offset(1).first
|
16
|
+
@ordered = Number.rank(:order).where(Number.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
|
17
|
+
@first.update :order => RankedModel::MAX_RANK_VALUE
|
18
|
+
@second.update :order => RankedModel::MAX_RANK_VALUE
|
19
|
+
}
|
20
|
+
|
21
|
+
context {
|
22
|
+
|
23
|
+
subject { Number.rank(:order).collect {|d| d.id } }
|
24
|
+
|
25
|
+
it { should == (@ordered[0..-2] + [@ordered[-1], @first.id, @second.id]) }
|
26
|
+
|
27
|
+
}
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "getting a position with keyword column name" do
|
32
|
+
|
33
|
+
subject { Number.first }
|
34
|
+
|
35
|
+
its(:order_rank) { should == 0 }
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -16,7 +16,7 @@ describe Player do
|
|
16
16
|
|
17
17
|
describe "setting the position of a record that already exists" do
|
18
18
|
it "sets the rank without error" do
|
19
|
-
expect{@players[:bob].
|
19
|
+
expect{@players[:bob].update! :score_position => 1}.to_not raise_error
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -62,3 +62,21 @@ describe RankedModel::Ranker, 'unless as Proc' do
|
|
62
62
|
}
|
63
63
|
end
|
64
64
|
end
|
65
|
+
|
66
|
+
describe RankedModel::Ranker, 'unless as lambda' do
|
67
|
+
context 'returns true' do
|
68
|
+
subject { RankedModel::Ranker.new(:overview, unless: ->(_) { true }).with(Class.new) }
|
69
|
+
its(:handle_ranking) { should == nil }
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'returns false' do
|
73
|
+
subject { RankedModel::Ranker.new(:overview, unless: ->(_) { false }).with(Class.new) }
|
74
|
+
|
75
|
+
it {
|
76
|
+
subject.expects(:update_index_from_position).once
|
77
|
+
subject.expects(:assure_unique_position).once
|
78
|
+
|
79
|
+
subject.handle_ranking
|
80
|
+
}
|
81
|
+
end
|
82
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler/setup'
|
3
|
+
require 'rspec/its'
|
3
4
|
|
4
5
|
require 'ranked-model'
|
6
|
+
require 'pry'
|
5
7
|
|
6
8
|
Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each {|f| require f}
|
7
9
|
|
8
10
|
# After the DB connection is setup
|
9
11
|
require 'database_cleaner'
|
10
12
|
|
13
|
+
# Uncomment this to see Active Record logging for tests
|
14
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
15
|
+
|
11
16
|
RSpec.configure do |config|
|
12
17
|
config.mock_with :mocha
|
13
18
|
|
@@ -24,6 +29,8 @@ RSpec.configure do |config|
|
|
24
29
|
DatabaseCleaner.clean
|
25
30
|
end
|
26
31
|
|
32
|
+
config.order = :random
|
33
|
+
Kernel.srand config.seed
|
27
34
|
end
|
28
35
|
|
29
36
|
RSpec::Matchers.define :define_constant do |expected|
|
@@ -12,7 +12,7 @@ describe Element do
|
|
12
12
|
}
|
13
13
|
@elements.each { |name, element|
|
14
14
|
element.reload
|
15
|
-
element.
|
15
|
+
element.update :combination_order_position => 0
|
16
16
|
}
|
17
17
|
@elements.each {|name, element| element.reload }
|
18
18
|
}
|
@@ -20,9 +20,9 @@ describe Element do
|
|
20
20
|
describe "rebalancing on an STI class should not affect the other class" do
|
21
21
|
|
22
22
|
before {
|
23
|
-
@elements[:helium].
|
24
|
-
@elements[:xenon].
|
25
|
-
@elements[:argon].
|
23
|
+
@elements[:helium].update :combination_order_position => :first
|
24
|
+
@elements[:xenon].update :combination_order_position => :first
|
25
|
+
@elements[:argon].update :combination_order_position => :last
|
26
26
|
|
27
27
|
TransitionMetal.ranker(:combination_order).with(@elements[:chromium]).instance_eval { rebalance_ranks }
|
28
28
|
}
|
@@ -40,16 +40,16 @@ describe Element do
|
|
40
40
|
describe "setting positions on STI classes" do
|
41
41
|
|
42
42
|
before {
|
43
|
-
@elements[:helium].
|
44
|
-
@elements[:xenon].
|
45
|
-
@elements[:argon].
|
46
|
-
|
47
|
-
@elements[:chromium].
|
48
|
-
@elements[:manganese].
|
49
|
-
@elements[:manganese].
|
50
|
-
@elements[:chromium].
|
51
|
-
@elements[:manganese].
|
52
|
-
@elements[:chromium].
|
43
|
+
@elements[:helium].update :combination_order_position => :first
|
44
|
+
@elements[:xenon].update :combination_order_position => :first
|
45
|
+
@elements[:argon].update :combination_order_position => :first
|
46
|
+
|
47
|
+
@elements[:chromium].update :combination_order_position => 1
|
48
|
+
@elements[:manganese].update :combination_order_position => 1
|
49
|
+
@elements[:manganese].update :combination_order_position => 0
|
50
|
+
@elements[:chromium].update :combination_order_position => 0
|
51
|
+
@elements[:manganese].update :combination_order_position => 0
|
52
|
+
@elements[:chromium].update :combination_order_position => 0
|
53
53
|
}
|
54
54
|
|
55
55
|
describe "NobleGas" do
|
@@ -81,16 +81,16 @@ describe Element do
|
|
81
81
|
describe "setting positions on STI classes" do
|
82
82
|
|
83
83
|
before {
|
84
|
-
@elements[:helium].
|
85
|
-
@elements[:xenon].
|
86
|
-
@elements[:argon].
|
87
|
-
|
88
|
-
@elements[:chromium].
|
89
|
-
@elements[:manganese].
|
90
|
-
@elements[:manganese].
|
91
|
-
@elements[:chromium].
|
92
|
-
@elements[:manganese].
|
93
|
-
@elements[:chromium].
|
84
|
+
@elements[:helium].update :combination_order_position => :first
|
85
|
+
@elements[:xenon].update :combination_order_position => :first
|
86
|
+
@elements[:argon].update :combination_order_position => :first
|
87
|
+
|
88
|
+
@elements[:chromium].update :combination_order_position => 1
|
89
|
+
@elements[:manganese].update :combination_order_position => 1
|
90
|
+
@elements[:manganese].update :combination_order_position => 0
|
91
|
+
@elements[:chromium].update :combination_order_position => 0
|
92
|
+
@elements[:manganese].update :combination_order_position => 0
|
93
|
+
@elements[:chromium].update :combination_order_position => 0
|
94
94
|
}
|
95
95
|
|
96
96
|
describe "NobleGas" do
|
@@ -12,7 +12,7 @@ describe Vehicle do
|
|
12
12
|
}
|
13
13
|
@vehicles.each { |name, vehicle|
|
14
14
|
vehicle.reload
|
15
|
-
vehicle.
|
15
|
+
vehicle.update :parking_order_position => 0
|
16
16
|
}
|
17
17
|
@vehicles.each {|name, vehicle| vehicle.reload }
|
18
18
|
}
|
@@ -20,8 +20,8 @@ describe Vehicle do
|
|
20
20
|
describe "ranking by STI parent" do
|
21
21
|
|
22
22
|
before {
|
23
|
-
@vehicles[:volvo].
|
24
|
-
@vehicles[:ford].
|
23
|
+
@vehicles[:volvo].update :parking_order_position => :first
|
24
|
+
@vehicles[:ford].update :parking_order_position => :first
|
25
25
|
}
|
26
26
|
|
27
27
|
describe "Vehicle" do
|
@@ -43,7 +43,7 @@ describe Vehicle do
|
|
43
43
|
describe "Vehicle" do
|
44
44
|
|
45
45
|
it "should have one ranker object" do
|
46
|
-
Vehicle.rankers.count.
|
46
|
+
expect(Vehicle.rankers.count).to eq(1)
|
47
47
|
end
|
48
48
|
|
49
49
|
subject { Vehicle.rankers.first }
|
@@ -57,7 +57,7 @@ describe Vehicle do
|
|
57
57
|
describe "MotorBike" do
|
58
58
|
|
59
59
|
it "should have one ranker object" do
|
60
|
-
MotorBike.rankers.count.
|
60
|
+
expect(MotorBike.rankers.count).to eq(1)
|
61
61
|
end
|
62
62
|
|
63
63
|
subject { MotorBike.rankers.first }
|
@@ -72,4 +72,4 @@ describe Vehicle do
|
|
72
72
|
|
73
73
|
end
|
74
74
|
|
75
|
-
end
|
75
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'logger'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
unless ENV['DB']
|
5
|
+
ENV['DB'] = 'sqlite'
|
6
|
+
end
|
7
7
|
|
8
8
|
ActiveRecord::Base.logger = Logger.new('tmp/ar_debug.log')
|
9
9
|
ActiveRecord::Base.configurations = YAML::load(IO.read('spec/support/database.yml'))
|
10
|
-
ActiveRecord::Base.establish_connection(
|
10
|
+
ActiveRecord::Base.establish_connection(ENV['DB'].to_sym)
|
11
11
|
|
12
12
|
ActiveRecord::Schema.define :version => 0 do
|
13
13
|
create_table :ducks, :force => true do |t|
|
@@ -21,6 +21,8 @@ ActiveRecord::Schema.define :version => 0 do
|
|
21
21
|
t.string :pond
|
22
22
|
end
|
23
23
|
|
24
|
+
add_index :ducks, [:landing_order, :lake_id, :flock_id], unique: true
|
25
|
+
|
24
26
|
create_table :wrong_scope_ducks, :force => true do |t|
|
25
27
|
t.string :name
|
26
28
|
t.integer :size
|
@@ -33,6 +35,12 @@ ActiveRecord::Schema.define :version => 0 do
|
|
33
35
|
t.string :pond
|
34
36
|
end
|
35
37
|
|
38
|
+
create_table :column_default_ducks, :force => true do |t|
|
39
|
+
t.string :name
|
40
|
+
t.integer :size, default: 0
|
41
|
+
t.string :pond
|
42
|
+
end
|
43
|
+
|
36
44
|
create_table :elements, :force => true do |t|
|
37
45
|
t.string :symbol
|
38
46
|
t.string :type
|
@@ -56,6 +64,11 @@ ActiveRecord::Schema.define :version => 0 do
|
|
56
64
|
t.string :city
|
57
65
|
t.integer :score
|
58
66
|
end
|
67
|
+
|
68
|
+
create_table :numbers, :force => true do |t|
|
69
|
+
t.float :value
|
70
|
+
t.integer :order
|
71
|
+
end
|
59
72
|
end
|
60
73
|
|
61
74
|
class Duck < ActiveRecord::Base
|
@@ -85,7 +98,12 @@ class WrongFieldDuck < ActiveRecord::Base
|
|
85
98
|
|
86
99
|
include RankedModel
|
87
100
|
ranks :age, :with_same => :non_existant_field
|
101
|
+
end
|
88
102
|
|
103
|
+
class ReallyWrongFieldDuck < ActiveRecord::Base
|
104
|
+
self.table_name = :wrong_field_ducks
|
105
|
+
include RankedModel
|
106
|
+
ranks :age, :with_same => [:name, :non_existant_field]
|
89
107
|
end
|
90
108
|
|
91
109
|
# Example for STI, ranking within each child class
|
@@ -132,7 +150,7 @@ class MotorBike < Vehicle
|
|
132
150
|
end
|
133
151
|
|
134
152
|
class Ego < ActiveRecord::Base
|
135
|
-
primary_key = :alternative_to_id
|
153
|
+
self.primary_key = :alternative_to_id
|
136
154
|
include RankedModel
|
137
155
|
ranks :size
|
138
156
|
end
|
@@ -140,3 +158,8 @@ end
|
|
140
158
|
class Player < ActiveRecord::Base
|
141
159
|
# don't add rank yet, do it in the specs
|
142
160
|
end
|
161
|
+
|
162
|
+
class Number < ActiveRecord::Base
|
163
|
+
include RankedModel
|
164
|
+
ranks :order
|
165
|
+
end
|