composite_primary_keys 10.0.3 → 10.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.rdoc +6 -0
- data/lib/composite_primary_keys.rb +0 -2
- data/lib/composite_primary_keys/associations/preloader/association.rb +2 -0
- data/lib/composite_primary_keys/attribute_methods/primary_key.rb +1 -1
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +10 -10
- data/lib/composite_primary_keys/locking/optimistic.rb +21 -31
- data/lib/composite_primary_keys/relation.rb +14 -3
- data/lib/composite_primary_keys/version.rb +1 -1
- data/scripts/console.rb +48 -48
- data/scripts/txt2html +76 -76
- data/scripts/txt2js +65 -65
- data/tasks/website.rake +18 -18
- data/test/README_tests.rdoc +56 -56
- data/test/connections/databases.yml +40 -30
- data/test/db_test.rb +52 -52
- data/test/fixtures/articles.yml +6 -6
- data/test/fixtures/capitol.rb +3 -3
- data/test/fixtures/capitols.yml +16 -16
- data/test/fixtures/comments.yml +15 -15
- data/test/fixtures/department.rb +5 -5
- data/test/fixtures/departments.yml +15 -15
- data/test/fixtures/dorms.yml +4 -4
- data/test/fixtures/group.rb +2 -2
- data/test/fixtures/groups.yml +6 -6
- data/test/fixtures/hack.rb +4 -4
- data/test/fixtures/hacks.yml +2 -2
- data/test/fixtures/membership_status.rb +2 -2
- data/test/fixtures/product.rb +9 -9
- data/test/fixtures/product_tariff.rb +5 -5
- data/test/fixtures/products.yml +11 -11
- data/test/fixtures/reading.rb +4 -4
- data/test/fixtures/readings.yml +10 -10
- data/test/fixtures/reference_code_using_composite_key_alias.rb +8 -8
- data/test/fixtures/reference_code_using_simple_key_alias.rb +8 -8
- data/test/fixtures/reference_codes.yml +28 -28
- data/test/fixtures/reference_types.yml +9 -9
- data/test/fixtures/restaurant.rb +9 -9
- data/test/fixtures/restaurants.yml +14 -14
- data/test/fixtures/restaurants_suburbs.yml +10 -10
- data/test/fixtures/room.rb +11 -11
- data/test/fixtures/room_assignment.rb +13 -13
- data/test/fixtures/room_assignments.yml +24 -24
- data/test/fixtures/room_attribute.rb +2 -2
- data/test/fixtures/room_attribute_assignment.rb +4 -4
- data/test/fixtures/room_attribute_assignments.yml +4 -4
- data/test/fixtures/room_attributes.yml +2 -2
- data/test/fixtures/rooms.yml +12 -12
- data/test/fixtures/seat.rb +5 -5
- data/test/fixtures/seats.yml +8 -8
- data/test/fixtures/street.rb +2 -2
- data/test/fixtures/streets.yml +16 -16
- data/test/fixtures/student.rb +3 -3
- data/test/fixtures/students.yml +15 -15
- data/test/fixtures/suburbs.yml +14 -14
- data/test/plugins/pagination.rb +405 -405
- data/test/plugins/pagination_helper.rb +135 -135
- data/test/setup.rb +50 -50
- data/test/test_aliases.rb +18 -18
- data/test/test_composite_arrays.rb +24 -24
- data/test/test_counter_cache.rb +30 -30
- data/test/test_dup.rb +37 -37
- data/test/test_exists.rb +39 -39
- data/test/test_miscellaneous.rb +32 -32
- data/test/test_pagination.rb +35 -35
- data/test/test_preload.rb +7 -0
- data/test/test_validations.rb +13 -13
- metadata +5 -6
- data/lib/composite_primary_keys/attribute_set/builder.rb +0 -22
data/test/test_counter_cache.rb
CHANGED
@@ -1,31 +1,31 @@
|
|
1
|
-
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
-
|
3
|
-
class TestCalculations < ActiveSupport::TestCase
|
4
|
-
fixtures :tariffs
|
5
|
-
|
6
|
-
def test_update_counter
|
7
|
-
tariff = tariffs(:flat)
|
8
|
-
assert_equal(50, tariff.amount)
|
9
|
-
Tariff.update_counters(tariff.id, :amount => 1)
|
10
|
-
tariff.reload
|
11
|
-
assert_equal(51, tariff.amount)
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_increment_counter
|
15
|
-
tariff = tariffs(:flat)
|
16
|
-
assert_equal(50, tariff.amount)
|
17
|
-
Tariff.increment_counter(:amount, tariff.id)
|
18
|
-
|
19
|
-
tariff.reload
|
20
|
-
assert_equal(51, tariff.amount)
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_decrement_counter
|
24
|
-
tariff = tariffs(:flat)
|
25
|
-
assert_equal(50, tariff.amount)
|
26
|
-
Tariff.decrement_counter(:amount, tariff.id)
|
27
|
-
|
28
|
-
tariff.reload
|
29
|
-
assert_equal(49, tariff.amount)
|
30
|
-
end
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestCalculations < ActiveSupport::TestCase
|
4
|
+
fixtures :tariffs
|
5
|
+
|
6
|
+
def test_update_counter
|
7
|
+
tariff = tariffs(:flat)
|
8
|
+
assert_equal(50, tariff.amount)
|
9
|
+
Tariff.update_counters(tariff.id, :amount => 1)
|
10
|
+
tariff.reload
|
11
|
+
assert_equal(51, tariff.amount)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_increment_counter
|
15
|
+
tariff = tariffs(:flat)
|
16
|
+
assert_equal(50, tariff.amount)
|
17
|
+
Tariff.increment_counter(:amount, tariff.id)
|
18
|
+
|
19
|
+
tariff.reload
|
20
|
+
assert_equal(51, tariff.amount)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_decrement_counter
|
24
|
+
tariff = tariffs(:flat)
|
25
|
+
assert_equal(50, tariff.amount)
|
26
|
+
Tariff.decrement_counter(:amount, tariff.id)
|
27
|
+
|
28
|
+
tariff.reload
|
29
|
+
assert_equal(49, tariff.amount)
|
30
|
+
end
|
31
31
|
end
|
data/test/test_dup.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
-
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
-
|
3
|
-
class TestClone < ActiveSupport::TestCase
|
4
|
-
fixtures :reference_types, :reference_codes
|
5
|
-
|
6
|
-
CLASSES = {
|
7
|
-
:single => {
|
8
|
-
:class => ReferenceType,
|
9
|
-
:primary_keys => :reference_type_id,
|
10
|
-
},
|
11
|
-
:dual => {
|
12
|
-
:class => ReferenceCode,
|
13
|
-
:primary_keys => [:reference_type_id, :reference_code],
|
14
|
-
},
|
15
|
-
}
|
16
|
-
|
17
|
-
def setup
|
18
|
-
self.class.classes = CLASSES
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_dup
|
22
|
-
testing_with do
|
23
|
-
clone = @first.dup
|
24
|
-
|
25
|
-
remove_keys = Array(@klass.primary_key).map(&:to_s)
|
26
|
-
remove_keys << Array(@klass.primary_key) # Rails 4 adds the PK to the attributes, so we want to remove it as well
|
27
|
-
assert_equal(@first.attributes.except(*remove_keys), clone.attributes.except(*remove_keys))
|
28
|
-
|
29
|
-
if composite?
|
30
|
-
@klass.primary_key.each do |key|
|
31
|
-
assert_nil(clone[key], "Primary key '#{key}' should be nil")
|
32
|
-
end
|
33
|
-
else
|
34
|
-
assert_nil(clone[@klass.primary_key], "Sole primary key should be nil")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestClone < ActiveSupport::TestCase
|
4
|
+
fixtures :reference_types, :reference_codes
|
5
|
+
|
6
|
+
CLASSES = {
|
7
|
+
:single => {
|
8
|
+
:class => ReferenceType,
|
9
|
+
:primary_keys => :reference_type_id,
|
10
|
+
},
|
11
|
+
:dual => {
|
12
|
+
:class => ReferenceCode,
|
13
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
14
|
+
},
|
15
|
+
}
|
16
|
+
|
17
|
+
def setup
|
18
|
+
self.class.classes = CLASSES
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_dup
|
22
|
+
testing_with do
|
23
|
+
clone = @first.dup
|
24
|
+
|
25
|
+
remove_keys = Array(@klass.primary_key).map(&:to_s)
|
26
|
+
remove_keys << Array(@klass.primary_key) # Rails 4 adds the PK to the attributes, so we want to remove it as well
|
27
|
+
assert_equal(@first.attributes.except(*remove_keys), clone.attributes.except(*remove_keys))
|
28
|
+
|
29
|
+
if composite?
|
30
|
+
@klass.primary_key.each do |key|
|
31
|
+
assert_nil(clone[key], "Primary key '#{key}' should be nil")
|
32
|
+
end
|
33
|
+
else
|
34
|
+
assert_nil(clone[@klass.primary_key], "Sole primary key should be nil")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
38
|
end
|
data/test/test_exists.rb
CHANGED
@@ -1,40 +1,40 @@
|
|
1
|
-
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
-
|
3
|
-
class TestExists < ActiveSupport::TestCase
|
4
|
-
fixtures :articles, :departments, :capitols
|
5
|
-
|
6
|
-
def test_id
|
7
|
-
assert(Article.exists?(1))
|
8
|
-
assert(!Article.exists?(-1))
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_array
|
12
|
-
assert(Article.exists?(['name = ?', 'Article One']))
|
13
|
-
assert(!Article.exists?(['name = ?', 'Article -1']))
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_hash
|
17
|
-
assert(Article.exists?('name' => 'Article One'))
|
18
|
-
assert(!Article.exists?('name' => 'Article -1'))
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_cpk_id
|
22
|
-
assert(Department.exists?(CompositePrimaryKeys::CompositeKeys.new([1,1])))
|
23
|
-
assert(!Department.exists?(CompositePrimaryKeys::CompositeKeys.new([1,-1])))
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_cpk_array_id
|
27
|
-
assert(Department.exists?([1,1]))
|
28
|
-
assert(!Department.exists?([1,-1]))
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_cpk_array_condition
|
32
|
-
assert(Department.exists?(['department_id = ? and location_id = ?', 1, 1]))
|
33
|
-
assert(!Department.exists?(['department_id = ? and location_id = ?', 1, -1]))
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_cpk_array_string_id
|
37
|
-
assert(Capitol.exists?(['The Netherlands', 'Amsterdam']))
|
38
|
-
assert(!Capitol.exists?(['The Netherlands', 'Paris']))
|
39
|
-
end
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestExists < ActiveSupport::TestCase
|
4
|
+
fixtures :articles, :departments, :capitols
|
5
|
+
|
6
|
+
def test_id
|
7
|
+
assert(Article.exists?(1))
|
8
|
+
assert(!Article.exists?(-1))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_array
|
12
|
+
assert(Article.exists?(['name = ?', 'Article One']))
|
13
|
+
assert(!Article.exists?(['name = ?', 'Article -1']))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_hash
|
17
|
+
assert(Article.exists?('name' => 'Article One'))
|
18
|
+
assert(!Article.exists?('name' => 'Article -1'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_cpk_id
|
22
|
+
assert(Department.exists?(CompositePrimaryKeys::CompositeKeys.new([1,1])))
|
23
|
+
assert(!Department.exists?(CompositePrimaryKeys::CompositeKeys.new([1,-1])))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_cpk_array_id
|
27
|
+
assert(Department.exists?([1,1]))
|
28
|
+
assert(!Department.exists?([1,-1]))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_cpk_array_condition
|
32
|
+
assert(Department.exists?(['department_id = ? and location_id = ?', 1, 1]))
|
33
|
+
assert(!Department.exists?(['department_id = ? and location_id = ?', 1, -1]))
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_cpk_array_string_id
|
37
|
+
assert(Capitol.exists?(['The Netherlands', 'Amsterdam']))
|
38
|
+
assert(!Capitol.exists?(['The Netherlands', 'Paris']))
|
39
|
+
end
|
40
40
|
end
|
data/test/test_miscellaneous.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
-
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
-
|
3
|
-
class TestMiscellaneous < ActiveSupport::TestCase
|
4
|
-
fixtures :reference_types, :reference_codes, :products
|
5
|
-
|
6
|
-
CLASSES = {
|
7
|
-
:single => {
|
8
|
-
:class => ReferenceType,
|
9
|
-
:primary_keys => :reference_type_id,
|
10
|
-
},
|
11
|
-
:dual => {
|
12
|
-
:class => ReferenceCode,
|
13
|
-
:primary_keys => [:reference_type_id, :reference_code],
|
14
|
-
},
|
15
|
-
}
|
16
|
-
|
17
|
-
def setup
|
18
|
-
self.class.classes = CLASSES
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_composite_class
|
22
|
-
testing_with do
|
23
|
-
assert_equal composite?, @klass.composite?
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_composite_instance
|
28
|
-
testing_with do
|
29
|
-
assert_equal composite?, @first.composite?
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestMiscellaneous < ActiveSupport::TestCase
|
4
|
+
fixtures :reference_types, :reference_codes, :products
|
5
|
+
|
6
|
+
CLASSES = {
|
7
|
+
:single => {
|
8
|
+
:class => ReferenceType,
|
9
|
+
:primary_keys => :reference_type_id,
|
10
|
+
},
|
11
|
+
:dual => {
|
12
|
+
:class => ReferenceCode,
|
13
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
14
|
+
},
|
15
|
+
}
|
16
|
+
|
17
|
+
def setup
|
18
|
+
self.class.classes = CLASSES
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_composite_class
|
22
|
+
testing_with do
|
23
|
+
assert_equal composite?, @klass.composite?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_composite_instance
|
28
|
+
testing_with do
|
29
|
+
assert_equal composite?, @first.composite?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/test/test_pagination.rb
CHANGED
@@ -1,36 +1,36 @@
|
|
1
|
-
#require File.expand_path('../abstract_unit', __FILE__)
|
2
|
-
#require 'plugins/pagination'
|
3
|
-
#
|
4
|
-
#class TestPagination < ActiveSupport::TestCase
|
5
|
-
# fixtures :reference_types, :reference_codes
|
6
|
-
#
|
7
|
-
# include ActionController::Pagination
|
8
|
-
# DEFAULT_PAGE_SIZE = 2
|
9
|
-
#
|
10
|
-
# attr_accessor :params
|
11
|
-
#
|
12
|
-
# CLASSES = {
|
13
|
-
# :single => {
|
14
|
-
# :class => ReferenceType,
|
15
|
-
# :primary_keys => :reference_type_id,
|
16
|
-
# :table => :reference_types,
|
17
|
-
# },
|
18
|
-
# :dual => {
|
19
|
-
# :class => ReferenceCode,
|
20
|
-
# :primary_keys => [:reference_type_id, :reference_code],
|
21
|
-
# :table => :reference_codes,
|
22
|
-
# },
|
23
|
-
# }
|
24
|
-
#
|
25
|
-
# def setup
|
26
|
-
# self.class.classes = CLASSES
|
27
|
-
# @params = {}
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# def test_paginate_all
|
31
|
-
# testing_with do
|
32
|
-
# @object_pages, @objects = paginate @klass_info[:table], :per_page => DEFAULT_PAGE_SIZE
|
33
|
-
# assert_equal 2, @objects.length, "Each page should have #{DEFAULT_PAGE_SIZE} items"
|
34
|
-
# end
|
35
|
-
# end
|
1
|
+
#require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
#require 'plugins/pagination'
|
3
|
+
#
|
4
|
+
#class TestPagination < ActiveSupport::TestCase
|
5
|
+
# fixtures :reference_types, :reference_codes
|
6
|
+
#
|
7
|
+
# include ActionController::Pagination
|
8
|
+
# DEFAULT_PAGE_SIZE = 2
|
9
|
+
#
|
10
|
+
# attr_accessor :params
|
11
|
+
#
|
12
|
+
# CLASSES = {
|
13
|
+
# :single => {
|
14
|
+
# :class => ReferenceType,
|
15
|
+
# :primary_keys => :reference_type_id,
|
16
|
+
# :table => :reference_types,
|
17
|
+
# },
|
18
|
+
# :dual => {
|
19
|
+
# :class => ReferenceCode,
|
20
|
+
# :primary_keys => [:reference_type_id, :reference_code],
|
21
|
+
# :table => :reference_codes,
|
22
|
+
# },
|
23
|
+
# }
|
24
|
+
#
|
25
|
+
# def setup
|
26
|
+
# self.class.classes = CLASSES
|
27
|
+
# @params = {}
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# def test_paginate_all
|
31
|
+
# testing_with do
|
32
|
+
# @object_pages, @objects = paginate @klass_info[:table], :per_page => DEFAULT_PAGE_SIZE
|
33
|
+
# assert_equal 2, @objects.length, "Each page should have #{DEFAULT_PAGE_SIZE} items"
|
34
|
+
# end
|
35
|
+
# end
|
36
36
|
#end
|
data/test/test_preload.rb
CHANGED
@@ -91,4 +91,11 @@ class TestPreload < ActiveSupport::TestCase
|
|
91
91
|
assert_equal(1, employees.first.groups_2.size)
|
92
92
|
assert_equal(2, employees.second.groups_2.size)
|
93
93
|
end
|
94
|
+
|
95
|
+
def test_preload_settings_inversion
|
96
|
+
users = User.preload(:readings).all
|
97
|
+
reading = users.first.readings.first
|
98
|
+
|
99
|
+
assert_equal(true, reading.association(:user).loaded?)
|
100
|
+
end
|
94
101
|
end
|
data/test/test_validations.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
-
|
3
|
-
class TestValidations < ActiveSupport::TestCase
|
4
|
-
fixtures :students, :dorms, :rooms, :room_assignments
|
5
|
-
|
6
|
-
def test_uniqueness_validation_persisted
|
7
|
-
room_assignment = RoomAssignment.find([1, 1, 1])
|
8
|
-
assert(room_assignment.valid?)
|
9
|
-
|
10
|
-
room_assignment = RoomAssignment.new(:student_id => 1, :dorm_id => 1, :room_id => 2)
|
11
|
-
assert(!room_assignment.valid?)
|
12
|
-
end
|
13
|
-
end
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestValidations < ActiveSupport::TestCase
|
4
|
+
fixtures :students, :dorms, :rooms, :room_assignments
|
5
|
+
|
6
|
+
def test_uniqueness_validation_persisted
|
7
|
+
room_assignment = RoomAssignment.find([1, 1, 1])
|
8
|
+
assert(room_assignment.valid?)
|
9
|
+
|
10
|
+
room_assignment = RoomAssignment.new(:student_id => 1, :dorm_id => 1, :room_id => 2)
|
11
|
+
assert(!room_assignment.valid?)
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composite_primary_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.0.
|
4
|
+
version: 10.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Savage
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 5.1.0
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 5.1.
|
22
|
+
version: 5.1.6
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: 5.1.0
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 5.1.
|
32
|
+
version: 5.1.6
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: rake
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,7 +112,6 @@ files:
|
|
112
112
|
- lib/composite_primary_keys/attribute_methods/primary_key.rb
|
113
113
|
- lib/composite_primary_keys/attribute_methods/read.rb
|
114
114
|
- lib/composite_primary_keys/attribute_methods/write.rb
|
115
|
-
- lib/composite_primary_keys/attribute_set/builder.rb
|
116
115
|
- lib/composite_primary_keys/autosave_association.rb
|
117
116
|
- lib/composite_primary_keys/base.rb
|
118
117
|
- lib/composite_primary_keys/composite_arrays.rb
|
@@ -279,7 +278,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
279
278
|
version: '0'
|
280
279
|
requirements: []
|
281
280
|
rubyforge_project:
|
282
|
-
rubygems_version: 2.7.
|
281
|
+
rubygems_version: 2.7.6
|
283
282
|
signing_key:
|
284
283
|
specification_version: 4
|
285
284
|
summary: Composite key support for ActiveRecord
|