uuid_associations-active_record 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/README.md +216 -6
- data/lib/uuid_associations/active_record/{method_definitions.rb → association_method_definitions.rb} +1 -1
- data/lib/uuid_associations/active_record/inline.rb +4 -2
- data/lib/uuid_associations/active_record/nested_attributes/uuid_finder.rb +49 -0
- data/lib/uuid_associations/active_record/nested_attributes_method_definitions.rb +27 -0
- data/lib/uuid_associations/active_record/railtie.rb +4 -2
- data/lib/uuid_associations/active_record/version.rb +1 -1
- data/spec/integration/nested_attributes/collection_spec.rb +65 -0
- data/spec/{uuid_associations → integration/relationship_definitions}/belongs_to_spec.rb +0 -0
- data/spec/{uuid_associations → integration/relationship_definitions}/has_and_belongs_to_many_spec.rb +0 -0
- data/spec/{uuid_associations → integration/relationship_definitions}/has_many_spec.rb +0 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/models/pet.rb +4 -0
- data/spec/support/models/post.rb +2 -0
- data/spec/support/models/toy.rb +5 -0
- data/spec/support/models/user.rb +1 -0
- data/spec/support/schema.rb +9 -2
- data/spec/unit/uuid_associations/active_record/nested_attributes/uuid_finder_spec.rb +71 -0
- data/uuid_associations-active_record.gemspec +2 -0
- metadata +18 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e1538fc45bf664d391c0a3b2b335247bdf0a66cc1f9133d3936000850175e9c
|
4
|
+
data.tar.gz: '092c5dad84a0a0ae487ecc61516b43b7d0b0e19fe7e3a2805f1811602dbbd5ee'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40acb305ecca02b540d97161942ef0bcf9161b1b5b07c4160df0adcb76a039e576da7a3afe53882bcb7501684b394170137f0c5df54df3eecf04fddf61ab7726
|
7
|
+
data.tar.gz: f064f70789721a9b789a76f096098548fa409ac69f63b818d8a232b3112a4ee58d524a72e2b7611c3a862596a7b22a17eb556655154cee828319aa7adbf59490
|
data/.travis.yml
CHANGED
@@ -5,9 +5,9 @@ cache: bundler
|
|
5
5
|
|
6
6
|
rvm:
|
7
7
|
- 2.2.10
|
8
|
-
- 2.3.
|
9
|
-
- 2.4.
|
10
|
-
- 2.5.
|
8
|
+
- 2.3.8
|
9
|
+
- 2.4.5
|
10
|
+
- 2.5.3
|
11
11
|
|
12
12
|
gemfile:
|
13
13
|
- gemfiles/active_record_4.2.gemfile
|
@@ -24,4 +24,4 @@ matrix:
|
|
24
24
|
- gemfile: gemfiles/active_record_edge.gemfile
|
25
25
|
rvm: 2.2.10
|
26
26
|
- gemfile: gemfiles/active_record_edge.gemfile
|
27
|
-
rvm: 2.3.
|
27
|
+
rvm: 2.3.8
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# UUID Associations ActiveRecord
|
2
2
|
[![Build Status](https://travis-ci.org/mcelicalderon/uuid_associations-active_record.svg?branch=master)](https://travis-ci.org/mcelicalderon/uuid_associations-active_record)
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/uuid_associations-active_record.svg)](https://badge.fury.io/rb/uuid_associations-active_record)
|
4
4
|
|
@@ -12,25 +12,235 @@ gem 'uuid_associations-active_record'
|
|
12
12
|
|
13
13
|
And then execute:
|
14
14
|
|
15
|
-
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
16
18
|
|
17
19
|
Or install it yourself as:
|
18
20
|
|
19
|
-
|
21
|
+
```bash
|
22
|
+
$ gem install uuid_associations-active_record
|
23
|
+
```
|
24
|
+
|
25
|
+
## Rationale
|
26
|
+
|
27
|
+
This gem is the result of some research I did to find out if using UUIDs as DB primary keys is a good thing
|
28
|
+
(Rails added support for this!). On the process
|
29
|
+
I ran into [this article](https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439) (among many others).
|
30
|
+
If you read the article you'll see how UUIDs have benefits over using sequential Int values as primary keys, but also how
|
31
|
+
you should be aware of what does that imply in terms of performance or even amount of storage used.
|
32
|
+
|
33
|
+
One of the author's conclusions is that you should use Int or Bigint columns as your primary keys, but also add a column
|
34
|
+
with a UUID that you can use to reference your records when exposing them to the outside world. If you finish reading the article
|
35
|
+
you'll find out that not even this is the perfect solution, but at least it's a huge improvement to exposing your sequential
|
36
|
+
primary keys. This gem helps you implement this approach.
|
20
37
|
|
21
38
|
## Usage
|
22
39
|
|
23
|
-
|
40
|
+
Adding the gem to your Gemfile is all you need for the gem to start working if you are using Rails. If you are not, you
|
41
|
+
you can always install the gem and require it manually (probably right after you require active_record). Take a look at
|
42
|
+
specs if you want to use the gem with plain ActiveRecord as that is how they are setup.
|
43
|
+
|
44
|
+
What this gem does is add some useful methods to your ActiveRecord models by calling the good old association methods like
|
45
|
+
`has_many`, `belongs_to`, `has_and_belongs_to_many`. As you may already know, calling these methods creates multiple
|
46
|
+
methods on the calling model for you. I'll explain the ones we are interested in in the next section.
|
47
|
+
|
48
|
+
This gem also adds a helpful mechanism to handle nested attributes. This will also be explained in the next section.
|
49
|
+
|
50
|
+
That's it! That is what the gem does. This will allow you to pass UUIDs to your update or create operations instead
|
51
|
+
of the actual IDs. Be aware that this will of course require an additional (but simple) DB query. That is the cost of
|
52
|
+
hiding the actual IDs (I'd say it's not too costly).
|
53
|
+
|
54
|
+
Also be aware that the initial version of this gem is not very configurable,
|
55
|
+
so the only thing it checks before creating the methods is that the right side association
|
56
|
+
on the caller model has a column named `uuid`, doesn't take the column type into account.
|
57
|
+
I have tested with string columns in SQlite3 and UUID columns in Postgres.
|
58
|
+
|
59
|
+
### Association Methods
|
60
|
+
|
61
|
+
Lets explore the next example:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
# app/models/user.rb
|
65
|
+
class User < ActiveRecord::Base
|
66
|
+
has_and_belongs_to_many :posts
|
67
|
+
# generates
|
68
|
+
#
|
69
|
+
# def post_ids=(ids)
|
70
|
+
# # Adds or deletes the association with posts based on the array of IDs received
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# def post_ids
|
74
|
+
# # returns an array with all the post IDs
|
75
|
+
# end
|
76
|
+
|
77
|
+
has_many :comments
|
78
|
+
# generates
|
79
|
+
#
|
80
|
+
# def comment_ids=(ids)
|
81
|
+
# # Adds or deletes the association with comments based on the array of IDs received
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# def comment_ids
|
85
|
+
# # returns an array with all the comment IDs
|
86
|
+
# end
|
87
|
+
end
|
88
|
+
|
89
|
+
# app/models/post.rb
|
90
|
+
class Post < ActiveRecord::Base
|
91
|
+
has_and_belongs_to_many :users
|
92
|
+
# generates
|
93
|
+
#
|
94
|
+
# def user_ids=(ids)
|
95
|
+
# # Adds or deletes the association with users based on the array of IDs received
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# def user_ids
|
99
|
+
# # returns an array with all the user IDs
|
100
|
+
# end
|
101
|
+
end
|
102
|
+
|
103
|
+
# app/models/comment.rb
|
104
|
+
class Comment < ActiveRecord::Base
|
105
|
+
belongs_to :user
|
106
|
+
# generates
|
107
|
+
#
|
108
|
+
# def user_id=(id)
|
109
|
+
# associates the comment with the user
|
110
|
+
# end
|
111
|
+
|
112
|
+
# def user_id
|
113
|
+
# returns the ID of the associated user
|
114
|
+
# end
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
This gem will add two new methods for each call to one of the association methods.
|
119
|
+
|
120
|
+
#### Generated Methods
|
121
|
+
|
122
|
+
Calling any of these methods will also add the following methods to your model:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
# app/models/user.rb
|
126
|
+
class User < ActiveRecord::Base
|
127
|
+
has_and_belongs_to_many :posts
|
128
|
+
# generates
|
129
|
+
#
|
130
|
+
# def post_uuids=(uuids)
|
131
|
+
# self.post_ids = Post.where(uuid: uuids).pluck(:id)
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# def post_uuids
|
135
|
+
# posts.pluck(:uuid)
|
136
|
+
# end
|
137
|
+
|
138
|
+
has_many :comments
|
139
|
+
# generates
|
140
|
+
#
|
141
|
+
# def comment_uuids=(uuids)
|
142
|
+
# self.comment_ids = Comment.where(uuid: uuids).pluck(:id)
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
# def comment_uuids
|
146
|
+
# comments.pluck(:uuid)
|
147
|
+
# end
|
148
|
+
end
|
149
|
+
|
150
|
+
# app/models/post.rb
|
151
|
+
class Post < ActiveRecord::Base
|
152
|
+
has_and_belongs_to_many :users
|
153
|
+
# generates
|
154
|
+
#
|
155
|
+
# def user_uuids=(uuids)
|
156
|
+
# self.user_ids = User.where(uuid: uuids).pluck(:id)
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# def user_uuids
|
160
|
+
# users.pluck(:uuid)
|
161
|
+
# end
|
162
|
+
end
|
163
|
+
|
164
|
+
# app/models/comment.rb
|
165
|
+
class Comment < ActiveRecord::Base
|
166
|
+
belongs_to :user
|
167
|
+
# generates
|
168
|
+
#
|
169
|
+
# def user_uuid=(uuid)
|
170
|
+
# self.user_id = User.find_by!(uuid: uuid)
|
171
|
+
# end
|
172
|
+
|
173
|
+
# def user_id
|
174
|
+
# user.uuid
|
175
|
+
# end
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
### Nested Attributes
|
180
|
+
|
181
|
+
Nested attributes don't generate additional methods, this gem just modifies one so you can update nested record using
|
182
|
+
the record's UUID instead of the actual ID. Let's explore the next example:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
class Post < ActiveRecord::Base
|
186
|
+
has_many :comments
|
187
|
+
|
188
|
+
accepts_nested_attributes_for :comments, allow_destroy: true
|
189
|
+
# generates
|
190
|
+
#
|
191
|
+
# def comments_attributes=(attributes)
|
192
|
+
# # allows to create or update comments using this method on Post
|
193
|
+
# end
|
194
|
+
end
|
195
|
+
```
|
196
|
+
|
197
|
+
ActiveRecord allows for `attributes` to be an array of hashes or a hash of hashes. Here are some examples of the payload
|
198
|
+
you can pass to `comments_attributes` by using this gem:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
# This is supported without this gem
|
202
|
+
[
|
203
|
+
{ id: 1, comment_body: 'updating comment with ID 1' },
|
204
|
+
{ id: 2, _destroy: true },
|
205
|
+
{ comment_body: 'this will create a new comment' }
|
206
|
+
]
|
207
|
+
|
208
|
+
# With the gem, you can use UUIDs instead
|
209
|
+
[
|
210
|
+
{ uuid: 'some-uuid', comment_body: 'updating comment with UUID: some-uuid' }.
|
211
|
+
{ uuid: 'other-uuid', _destroy: true },
|
212
|
+
{ comment_body: 'this will create a new comment' }
|
213
|
+
]
|
214
|
+
```
|
215
|
+
|
216
|
+
Here are some things to take into account:
|
217
|
+
|
218
|
+
1. If the nested model (Comment in the example) does not have a column named `uuid`, the gem will take no action, will
|
219
|
+
just preserve the original behavior.
|
220
|
+
1. If the hash has both the `:id` and `:uuid` keys, the record will be fetched by `id`, and `uuid` will be passed as an attribute.
|
221
|
+
1. When the hash has a `:uuid` key and no record is found for that key, a new record will be created using that UUID
|
222
|
+
(this will change to raise a not found error instead).
|
223
|
+
|
224
|
+
## Future Work
|
225
|
+
|
226
|
+
1. Not commonly used by me, but testing and adding these methods to a `has_one` relationship.
|
227
|
+
1. Raise not found error if the array of UUIDs is bigger that the array
|
228
|
+
of IDs fetched with the `where` statement (ActiveRecord's behavior).
|
24
229
|
|
25
230
|
## Development
|
26
231
|
|
27
232
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
28
233
|
|
29
|
-
To
|
234
|
+
To run the specs with all the supported versions of ActiveRecord you can use:
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
$ bundle exec appraisal install
|
238
|
+
$ bundle exec appraisal rspec
|
239
|
+
```
|
30
240
|
|
31
241
|
## Contributing
|
32
242
|
|
33
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
243
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mcelicalderon/uuid_associations-active_record.
|
34
244
|
|
35
245
|
## License
|
36
246
|
|
data/lib/uuid_associations/active_record/{method_definitions.rb → association_method_definitions.rb}
RENAMED
@@ -3,7 +3,7 @@ require 'uuid_associations/active_record/relationship_definitions/has_many'
|
|
3
3
|
|
4
4
|
module UuidAssociations
|
5
5
|
module ActiveRecord
|
6
|
-
module
|
6
|
+
module AssociationMethodDefinitions
|
7
7
|
def has_many(name, scope = nil, **options, &extension)
|
8
8
|
original_payload = super(name, scope, options, &extension)
|
9
9
|
RelationshipDefinitions::HasMany.define_accesors_for(self, original_payload, name)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'active_record/associations'
|
3
|
-
require 'uuid_associations/active_record/
|
3
|
+
require 'uuid_associations/active_record/association_method_definitions'
|
4
|
+
require 'uuid_associations/active_record/nested_attributes_method_definitions'
|
4
5
|
|
5
|
-
::ActiveRecord::
|
6
|
+
::ActiveRecord::Base.extend(UuidAssociations::ActiveRecord::AssociationMethodDefinitions)
|
7
|
+
::ActiveRecord::Base.prepend(UuidAssociations::ActiveRecord::NestedAttributesMethodDefinitions)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module UuidAssociations
|
2
|
+
module ActiveRecord
|
3
|
+
module NestedAttributes
|
4
|
+
class UuidFinder
|
5
|
+
def self.replaced_uuids_with_ids(association_klass, attribute_collection)
|
6
|
+
new(association_klass, attribute_collection).call
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(association_klass, attribute_collection)
|
10
|
+
@association_klass = association_klass
|
11
|
+
@attribute_collection = attribute_collection
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
to_replace, to_keep = attribute_collection.partition do |attributes|
|
16
|
+
symbol_keys = attributes.keys.map(&:to_sym)
|
17
|
+
|
18
|
+
(symbol_keys & [:uuid, :id]) == [:uuid]
|
19
|
+
end
|
20
|
+
|
21
|
+
uuids_to_find = to_replace.map { |element| element[:uuid] }
|
22
|
+
found_records = association_klass.where(uuid: uuids_to_find)
|
23
|
+
|
24
|
+
replaced = to_replace.each_with_object([]) do |attributes, collection|
|
25
|
+
uuid = attributes.delete(:uuid)
|
26
|
+
|
27
|
+
record = found_records.find { |found_record| found_record.uuid == uuid }
|
28
|
+
|
29
|
+
collection << if record.blank?
|
30
|
+
attributes
|
31
|
+
else
|
32
|
+
attributes.merge(id: record.id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
to_keep + replaced
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def attribute_collection
|
42
|
+
@attribute_collection.instance_of?(Hash) ? @attribute_collection.values : @attribute_collection
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :association_klass
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'uuid_associations/active_record/nested_attributes/uuid_finder'
|
2
|
+
|
3
|
+
module UuidAssociations
|
4
|
+
module ActiveRecord
|
5
|
+
module NestedAttributesMethodDefinitions
|
6
|
+
private
|
7
|
+
|
8
|
+
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
|
9
|
+
association_klass = association(association_name).reflection.klass
|
10
|
+
unless nested_association_uuid_searchable?(association_klass, attributes_collection)
|
11
|
+
return super(association_name, attributes_collection)
|
12
|
+
end
|
13
|
+
|
14
|
+
replaced_attributes = ActiveRecord::NestedAttributes::UuidFinder.replaced_uuids_with_ids(
|
15
|
+
association_klass,
|
16
|
+
attributes_collection
|
17
|
+
)
|
18
|
+
super(association_name, replaced_attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
def nested_association_uuid_searchable?(association_klass, attributes_collection)
|
22
|
+
association_klass.column_names.include?('uuid') &&
|
23
|
+
(attributes_collection.instance_of?(Hash) || attributes_collection.instance_of?(Array))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require 'uuid_associations/active_record/
|
1
|
+
require 'uuid_associations/active_record/association_method_definitions'
|
2
|
+
require 'uuid_associations/active_record/nested_attributes_method_definitions'
|
2
3
|
|
3
4
|
module UuidAssociations
|
4
5
|
module ActiveRecord
|
@@ -7,7 +8,8 @@ module UuidAssociations
|
|
7
8
|
ActiveSupport.on_load(:active_record) do
|
8
9
|
::ActiveRecord::Associations.eager_load!
|
9
10
|
|
10
|
-
extend
|
11
|
+
extend(UuidAssociations::ActiveRecord::AssociationMethodDefinitions)
|
12
|
+
prepend(UuidAssociations::ActiveRecord::NestedAttributesMethodDefinitions)
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
RSpec.describe 'nested attributes for collection' do
|
2
|
+
context 'when nested association has no UUID column' do
|
3
|
+
let(:pet) { Pet.create!(name: 'Simba') }
|
4
|
+
|
5
|
+
it 'does not call UUID finder' do
|
6
|
+
expect(UuidAssociations::ActiveRecord::NestedAttributes::UuidFinder).not_to receive(:replaced_uuids_with_ids)
|
7
|
+
|
8
|
+
pet.update(toys_attributes: [{ name: 'no-uuid-here ;)' }])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when creating a new record' do
|
13
|
+
it 'creates nested resources when not existing UUID is passed' do
|
14
|
+
expect do
|
15
|
+
Post.create!(
|
16
|
+
uuid: SecureRandom.uuid,
|
17
|
+
content: 'post',
|
18
|
+
comments_attributes: [
|
19
|
+
body: 'New comment',
|
20
|
+
uuid: SecureRandom.uuid
|
21
|
+
]
|
22
|
+
)
|
23
|
+
end.to change(Post, :count).from(0).to(1)
|
24
|
+
.and change(Comment, :count).from(0).to(1)
|
25
|
+
|
26
|
+
expect(Post.first.comments.count).to eq(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'creates nested resources when no UUID or ID is passed' do
|
30
|
+
expect do
|
31
|
+
Post.create!(
|
32
|
+
uuid: SecureRandom.uuid,
|
33
|
+
content: 'post',
|
34
|
+
comments_attributes: [
|
35
|
+
body: 'New comment'
|
36
|
+
]
|
37
|
+
)
|
38
|
+
end.to change(Post, :count).from(0).to(1)
|
39
|
+
.and change(Comment, :count).from(0).to(1)
|
40
|
+
|
41
|
+
expect(Post.first.comments.count).to eq(1)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when updating existing records' do
|
46
|
+
let(:comment_uuid) { SecureRandom.uuid }
|
47
|
+
let(:post) { Post.create!(uuid: SecureRandom.uuid, content: 'My post') }
|
48
|
+
let!(:comment) { Comment.create!(post: post, body: 'My comment', uuid: comment_uuid) }
|
49
|
+
|
50
|
+
it 'updates nested records when a UUID is passed and no ID' do
|
51
|
+
expect do
|
52
|
+
post.update(comments_attributes: [{ uuid: comment.uuid, body: 'updated comment' }])
|
53
|
+
comment.reload
|
54
|
+
end.to change(comment, :body).from('My comment').to('updated comment')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'updates nested records by ID if ID is passed' do
|
58
|
+
expect do
|
59
|
+
post.update(comments_attributes: [{ id: comment.id, uuid: 'new-uuid', body: 'updated comment' }])
|
60
|
+
comment.reload
|
61
|
+
end.to change(comment, :body).from('My comment').to('updated comment')
|
62
|
+
.and change(comment, :uuid).from(comment_uuid).to('new-uuid')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
File without changes
|
data/spec/{uuid_associations → integration/relationship_definitions}/has_and_belongs_to_many_spec.rb
RENAMED
File without changes
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
@@ -6,6 +6,8 @@ require 'support/models/team'
|
|
6
6
|
require 'support/models/user'
|
7
7
|
require 'support/models/post'
|
8
8
|
require 'support/models/comment'
|
9
|
+
require 'support/models/pet'
|
10
|
+
require 'support/models/toy'
|
9
11
|
|
10
12
|
RSpec.configure do |config|
|
11
13
|
# Enable flags like --only-failures and --next-failure
|
data/spec/support/models/pet.rb
CHANGED
data/spec/support/models/post.rb
CHANGED
data/spec/support/models/user.rb
CHANGED
data/spec/support/schema.rb
CHANGED
@@ -10,7 +10,7 @@ ActiveRecord::Schema.define version: 0 do
|
|
10
10
|
t.timestamps
|
11
11
|
end
|
12
12
|
|
13
|
-
create_table :teams_users,
|
13
|
+
create_table :teams_users, id: false do |t|
|
14
14
|
t.integer :user_id, null: false
|
15
15
|
t.integer :team_id, null: false
|
16
16
|
end
|
@@ -22,7 +22,7 @@ ActiveRecord::Schema.define version: 0 do
|
|
22
22
|
t.timestamps
|
23
23
|
end
|
24
24
|
|
25
|
-
create_table :pets_users,
|
25
|
+
create_table :pets_users, id: false do |t|
|
26
26
|
t.integer :user_id, null: false
|
27
27
|
t.integer :pet_id, null: false
|
28
28
|
end
|
@@ -34,6 +34,13 @@ ActiveRecord::Schema.define version: 0 do
|
|
34
34
|
t.timestamps
|
35
35
|
end
|
36
36
|
|
37
|
+
create_table :toys do |t|
|
38
|
+
t.string :name, null: false
|
39
|
+
t.belongs_to :pet, foreign_key: { on_delete: :cascade }
|
40
|
+
|
41
|
+
t.timestamps
|
42
|
+
end
|
43
|
+
|
37
44
|
create_table :posts do |t|
|
38
45
|
t.belongs_to :user, foreign_key: { on_delete: :cascade }
|
39
46
|
t.string :uuid
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'uuid_associations/active_record/nested_attributes/uuid_finder'
|
2
|
+
|
3
|
+
RSpec.describe UuidAssociations::ActiveRecord::NestedAttributes::UuidFinder do
|
4
|
+
describe '.replaced_uuids_with_ids' do
|
5
|
+
subject { described_class.replaced_uuids_with_ids(klass, attribute_collection) }
|
6
|
+
|
7
|
+
let(:post) { Post.create!(content: 'content', uuid: SecureRandom.uuid) }
|
8
|
+
let(:comment) { Comment.create!(post: post, body: 'my comment', uuid: SecureRandom.uuid) }
|
9
|
+
let(:klass) { Comment }
|
10
|
+
|
11
|
+
context 'when attributes come as an array' do
|
12
|
+
context 'when UUID is present, but ID is not' do
|
13
|
+
let(:attribute_collection) { [{ uuid: comment.uuid, body: 'updated comment' }] }
|
14
|
+
|
15
|
+
it { is_expected.to contain_exactly(id: comment.id, body: 'updated comment') }
|
16
|
+
|
17
|
+
context 'when record with specified UUID does not exist on the sytem' do
|
18
|
+
let(:attribute_collection) { [{ uuid: SecureRandom.uuid, body: 'new comment :/' }] }
|
19
|
+
|
20
|
+
it { is_expected.to match_array(attribute_collection) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when both UUID and ID are present' do
|
25
|
+
let(:attribute_collection) do
|
26
|
+
[
|
27
|
+
{ uuid: comment.uuid, id: comment.id, body: 'updated comment' },
|
28
|
+
{ body: 'new comment' }
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
it do
|
33
|
+
is_expected.to contain_exactly(
|
34
|
+
{ uuid: comment.uuid, id: comment.id, body: 'updated comment' },
|
35
|
+
{ body: 'new comment' }
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when attributes come as a hash' do
|
42
|
+
context 'when UUID is present, but ID is not' do
|
43
|
+
let(:attribute_collection) { { first: { uuid: comment.uuid, body: 'updated comment' } } }
|
44
|
+
|
45
|
+
it { is_expected.to contain_exactly(id: comment.id, body: 'updated comment') }
|
46
|
+
|
47
|
+
context 'when record with specified UUID does not exist on the sytem' do
|
48
|
+
let(:attribute_collection) { { first: { uuid: SecureRandom.uuid, body: 'new comment :/' } } }
|
49
|
+
|
50
|
+
it { is_expected.to match_array(attribute_collection.values) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when both UUID and ID are present' do
|
55
|
+
let(:attribute_collection) do
|
56
|
+
{
|
57
|
+
first: { uuid: comment.uuid, id: comment.id, body: 'updated comment' },
|
58
|
+
second: { body: 'new comment' }
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
it do
|
63
|
+
is_expected.to contain_exactly(
|
64
|
+
{ uuid: comment.uuid, id: comment.id, body: 'updated comment' },
|
65
|
+
{ body: 'new comment' }
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
+
spec.required_ruby_version = '>= 2.1'
|
23
|
+
|
22
24
|
spec.add_dependency 'activerecord', '>= 4.2', '< 6.0'
|
23
25
|
|
24
26
|
spec.add_development_dependency 'appraisal', '~> 2.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uuid_associations-active_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mario Celi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -139,23 +139,28 @@ files:
|
|
139
139
|
- gemfiles/active_record_5.2.gemfile
|
140
140
|
- gemfiles/active_record_edge.gemfile
|
141
141
|
- lib/uuid_associations/active_record.rb
|
142
|
+
- lib/uuid_associations/active_record/association_method_definitions.rb
|
142
143
|
- lib/uuid_associations/active_record/inline.rb
|
143
|
-
- lib/uuid_associations/active_record/
|
144
|
+
- lib/uuid_associations/active_record/nested_attributes/uuid_finder.rb
|
145
|
+
- lib/uuid_associations/active_record/nested_attributes_method_definitions.rb
|
144
146
|
- lib/uuid_associations/active_record/railtie.rb
|
145
147
|
- lib/uuid_associations/active_record/relationship_definitions/base.rb
|
146
148
|
- lib/uuid_associations/active_record/relationship_definitions/belongs_to.rb
|
147
149
|
- lib/uuid_associations/active_record/relationship_definitions/has_many.rb
|
148
150
|
- lib/uuid_associations/active_record/version.rb
|
151
|
+
- spec/integration/nested_attributes/collection_spec.rb
|
152
|
+
- spec/integration/relationship_definitions/belongs_to_spec.rb
|
153
|
+
- spec/integration/relationship_definitions/has_and_belongs_to_many_spec.rb
|
154
|
+
- spec/integration/relationship_definitions/has_many_spec.rb
|
149
155
|
- spec/spec_helper.rb
|
150
156
|
- spec/support/models/comment.rb
|
151
157
|
- spec/support/models/pet.rb
|
152
158
|
- spec/support/models/post.rb
|
153
159
|
- spec/support/models/team.rb
|
160
|
+
- spec/support/models/toy.rb
|
154
161
|
- spec/support/models/user.rb
|
155
162
|
- spec/support/schema.rb
|
156
|
-
- spec/uuid_associations/
|
157
|
-
- spec/uuid_associations/has_and_belongs_to_many_spec.rb
|
158
|
-
- spec/uuid_associations/has_many_spec.rb
|
163
|
+
- spec/unit/uuid_associations/active_record/nested_attributes/uuid_finder_spec.rb
|
159
164
|
- uuid_associations-active_record.gemspec
|
160
165
|
homepage: https://github.com/mcelicalderon/uuid_associations-active_record
|
161
166
|
licenses:
|
@@ -169,7 +174,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
169
174
|
requirements:
|
170
175
|
- - ">="
|
171
176
|
- !ruby/object:Gem::Version
|
172
|
-
version: '
|
177
|
+
version: '2.1'
|
173
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
179
|
requirements:
|
175
180
|
- - ">="
|
@@ -182,13 +187,16 @@ signing_key:
|
|
182
187
|
specification_version: 4
|
183
188
|
summary: Helper methods for UUID associations in Active Record
|
184
189
|
test_files:
|
190
|
+
- spec/integration/nested_attributes/collection_spec.rb
|
191
|
+
- spec/integration/relationship_definitions/belongs_to_spec.rb
|
192
|
+
- spec/integration/relationship_definitions/has_and_belongs_to_many_spec.rb
|
193
|
+
- spec/integration/relationship_definitions/has_many_spec.rb
|
185
194
|
- spec/spec_helper.rb
|
186
195
|
- spec/support/models/comment.rb
|
187
196
|
- spec/support/models/pet.rb
|
188
197
|
- spec/support/models/post.rb
|
189
198
|
- spec/support/models/team.rb
|
199
|
+
- spec/support/models/toy.rb
|
190
200
|
- spec/support/models/user.rb
|
191
201
|
- spec/support/schema.rb
|
192
|
-
- spec/uuid_associations/
|
193
|
-
- spec/uuid_associations/has_and_belongs_to_many_spec.rb
|
194
|
-
- spec/uuid_associations/has_many_spec.rb
|
202
|
+
- spec/unit/uuid_associations/active_record/nested_attributes/uuid_finder_spec.rb
|