deferred_associations 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +4 -0
- data/Readme.markdown +17 -1
- data/deferred_associations.gemspec +2 -2
- data/lib/array_to_association_wrapper.rb +8 -4
- data/lib/has_and_belongs_to_many_with_deferred_save.rb +13 -6
- data/lib/has_many_with_deferred_save.rb +12 -7
- data/spec/habtm_ar4_spec.rb +9 -9
- data/spec/has_and_belongs_to_many_with_deferred_save_spec.rb +23 -7
- data/spec/has_many_with_deferred_save_spec.rb +1 -1
- data/spec/models/room.rb +5 -1
- data/spec/spec_helper.rb +7 -3
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9b5f99b0963214fda3ba967f00208785fc8732e
|
4
|
+
data.tar.gz: f0617535e1cd7d2ecd07be537bdb90e19bf75a38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18e808f2555625e6cf6a6a25b3e8966a056c71fac0814475ed4a2745574822ce9c5635b65c9283407da093eac6de784f650cc4ee49ec57a6c5d7fb6e5936662d
|
7
|
+
data.tar.gz: 0d0801311814c39772939b09f28936bebd89e6b115c59d0dfbf3b47d2fd6f7c34ce70f0b6a9af5b851e289d565c393935968949feda58dead0743af97c7d259f
|
data/CHANGELOG
CHANGED
data/Readme.markdown
CHANGED
@@ -46,7 +46,7 @@ end
|
|
46
46
|
Compatibility
|
47
47
|
=============
|
48
48
|
|
49
|
-
Tested with Rails 2.3.18, 3.2.22, 4.1.
|
49
|
+
Tested with Rails 2.3.18, 3.2.22, 4.1.16, 4.2.20, 5.1.4 on Ruby 1.9.3, 2.2.8, 2.3.5 and JRuby 1.7, JRuby 9.1.9.0
|
50
50
|
|
51
51
|
Note, that Rails 3.2.14 associations are partly broken under JRuby cause of https://github.com/rails/rails/issues/11595
|
52
52
|
You'll need to upgrade activerecord-jdbc-adapter to >= 1.3.0.beta1, if you want to use this combination.
|
@@ -94,6 +94,22 @@ methods are not working:
|
|
94
94
|
room.updated_at # => got touched!
|
95
95
|
```
|
96
96
|
|
97
|
+
4. If you use the ID getter, you get a copy of the IDs of the objects. So changing the entries in the array won't change
|
98
|
+
the IDs for real.
|
99
|
+
Rails 5 acts a little bit different - it lets you change the entry, but also doesn't save it.
|
100
|
+
deferred_associations will act the same way as in Rails 3&4.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
room = Room.find(...)
|
104
|
+
room.people_ids # [1]
|
105
|
+
room.people_ids << 2
|
106
|
+
room.people_ids # Rails 4: [1]
|
107
|
+
room.people_ids # Rails 5: [1, 2], but with deferred associations, it stays at [1]
|
108
|
+
room.save!
|
109
|
+
room.reload
|
110
|
+
room.people_ids # Rails 4&5: [1] # even Rails 5 doesn't save the changed array
|
111
|
+
```
|
112
|
+
|
97
113
|
Bugs
|
98
114
|
====
|
99
115
|
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'deferred_associations'
|
5
|
-
s.version = '0.6.
|
5
|
+
s.version = '0.6.5'
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ['Martin Koerner', 'Tyler Rick', 'Alessio Caiazza']
|
9
|
-
s.date = '
|
9
|
+
s.date = '2017-12-23'
|
10
10
|
s.description = "Makes ActiveRecord defer/postpone saving the records you add to an habtm (has_and_belongs_to_many) or has_many\n association until you call model.save, allowing validation in the style of normal attributes. Additionally you\n can check inside before_save filters, if the association was altered."
|
11
11
|
s.email = 'martin.koerner@objectfab.de'
|
12
12
|
s.licenses = 'MIT'
|
@@ -20,7 +20,8 @@ class ArrayToAssociationWrapper < Array
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
alias_method(:include_without_deferred_save?, :include?)
|
24
|
+
alias_method(:include?, :include_with_deferred_save?)
|
24
25
|
|
25
26
|
def find_with_deferred_save(*args)
|
26
27
|
if @association_owner.present?
|
@@ -30,7 +31,8 @@ class ArrayToAssociationWrapper < Array
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
+
alias_method(:find_without_deferred_save, :find)
|
35
|
+
alias_method(:find, :find_with_deferred_save)
|
34
36
|
|
35
37
|
def first_with_deferred_save(*args)
|
36
38
|
if @association_owner.present?
|
@@ -40,7 +42,8 @@ class ArrayToAssociationWrapper < Array
|
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
43
|
-
|
45
|
+
alias_method(:first_without_deferred_save, :first)
|
46
|
+
alias_method(:first, :first_with_deferred_save)
|
44
47
|
|
45
48
|
def last_with_deferred_save(*args)
|
46
49
|
if @association_owner.present?
|
@@ -50,7 +53,8 @@ class ArrayToAssociationWrapper < Array
|
|
50
53
|
end
|
51
54
|
end
|
52
55
|
|
53
|
-
|
56
|
+
alias_method(:last_without_deferred_save, :last)
|
57
|
+
alias_method(:last, :last_with_deferred_save)
|
54
58
|
|
55
59
|
define_method :method_missing do |method, *args|
|
56
60
|
# puts "#{self.class}.method_missing(#{method}) (#{collection_without_deferred_save.inspect})"
|
@@ -41,8 +41,10 @@ module ActiveRecord
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
|
44
|
+
alias_method(:"#{collection_name}_without_deferred_save=", :"#{collection_name}=")
|
45
|
+
alias_method(:"#{collection_name}=", :"#{collection_name}_with_deferred_save=")
|
46
|
+
alias_method(:"#{collection_name}_without_deferred_save", :"#{collection_name}")
|
47
|
+
alias_method(:"#{collection_name}", :"#{collection_name}_with_deferred_save")
|
46
48
|
|
47
49
|
define_method "#{collection_singular_ids}_with_deferred_save" do |*method_args|
|
48
50
|
if send("use_original_collection_reader_behavior_for_#{collection_name}")
|
@@ -53,7 +55,8 @@ module ActiveRecord
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
|
58
|
+
alias_method(:"#{collection_singular_ids}_without_deferred_save", :"#{collection_singular_ids}")
|
59
|
+
alias_method(:"#{collection_singular_ids}", :"#{collection_singular_ids}_with_deferred_save")
|
57
60
|
|
58
61
|
# only needed for ActiveRecord >= 3.0
|
59
62
|
if ActiveRecord::VERSION::STRING >= '3'
|
@@ -63,7 +66,9 @@ module ActiveRecord
|
|
63
66
|
new_values = reflection_wrapper.klass.find(ids)
|
64
67
|
send("#{collection_name}=", new_values)
|
65
68
|
end
|
66
|
-
|
69
|
+
|
70
|
+
alias_method(:"#{collection_singular_ids}_without_deferred_save=", :"#{collection_singular_ids}=")
|
71
|
+
alias_method(:"#{collection_singular_ids}=", :"#{collection_singular_ids}_with_deferred_save=")
|
67
72
|
end
|
68
73
|
|
69
74
|
define_method "do_#{collection_name}_save!" do
|
@@ -87,7 +92,7 @@ module ActiveRecord
|
|
87
92
|
end
|
88
93
|
true
|
89
94
|
end
|
90
|
-
after_save "do_#{collection_name}_save!"
|
95
|
+
after_save :"do_#{collection_name}_save!"
|
91
96
|
|
92
97
|
define_method "reload_with_deferred_save_for_#{collection_name}" do |*method_args|
|
93
98
|
# Reload from the *database*, discarding any unsaved changes.
|
@@ -97,7 +102,9 @@ module ActiveRecord
|
|
97
102
|
# unsaved_collection that it had before the reload.
|
98
103
|
end
|
99
104
|
end
|
100
|
-
|
105
|
+
|
106
|
+
alias_method(:"reload_without_deferred_save_for_#{collection_name}", :reload)
|
107
|
+
alias_method(:reload, :"reload_with_deferred_save_for_#{collection_name}")
|
101
108
|
|
102
109
|
define_method "initialize_unsaved_#{collection_name}" do |*method_args|
|
103
110
|
elements = send("#{collection_name}_without_deferred_save", *method_args)
|
@@ -13,7 +13,7 @@ module ActiveRecord
|
|
13
13
|
logger.warn "You are using the option :through on #{name}##{collection_name}. This was not tested very much with has_many_with_deferred_save. Please write many tests for your functionality!"
|
14
14
|
end
|
15
15
|
|
16
|
-
after_save "hmwds_update_#{collection_name}"
|
16
|
+
after_save :"hmwds_update_#{collection_name}"
|
17
17
|
|
18
18
|
define_obj_setter collection_name
|
19
19
|
define_obj_getter collection_name
|
@@ -30,8 +30,8 @@ module ActiveRecord
|
|
30
30
|
attribute_will_change!(collection_name) if objs != send("#{collection_name}_without_deferred_save")
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
alias_method(:"#{collection_name}_without_deferred_save=", :"#{collection_name}=")
|
34
|
+
alias_method(:"#{collection_name}=", :"#{collection_name}_with_deferred_save=")
|
35
35
|
end
|
36
36
|
|
37
37
|
def define_obj_getter(collection_name)
|
@@ -55,7 +55,8 @@ module ActiveRecord
|
|
55
55
|
result
|
56
56
|
end
|
57
57
|
|
58
|
-
|
58
|
+
alias_method(:"#{collection_name}_without_deferred_save", :"#{collection_name}")
|
59
|
+
alias_method(:"#{collection_name}", :"#{collection_name}_with_deferred_save")
|
59
60
|
end
|
60
61
|
|
61
62
|
def define_id_setter(collection_name, collection_singular_ids)
|
@@ -66,7 +67,9 @@ module ActiveRecord
|
|
66
67
|
new_values = send("#{collection_name}_without_deferred_save").klass.find(ids)
|
67
68
|
send("#{collection_name}=", new_values)
|
68
69
|
end
|
69
|
-
|
70
|
+
|
71
|
+
alias_method(:"#{collection_singular_ids}_without_deferred_save=", :"#{collection_singular_ids}=")
|
72
|
+
alias_method(:"#{collection_singular_ids}=", :"#{collection_singular_ids}_with_deferred_save=")
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
@@ -74,7 +77,8 @@ module ActiveRecord
|
|
74
77
|
define_method "#{collection_singular_ids}_with_deferred_save" do
|
75
78
|
send(collection_name).map { |e| e[:id] }
|
76
79
|
end
|
77
|
-
|
80
|
+
alias_method(:"#{collection_singular_ids}_without_deferred_save", :"#{collection_singular_ids}")
|
81
|
+
alias_method(:"#{collection_singular_ids}", :"#{collection_singular_ids}_with_deferred_save")
|
78
82
|
end
|
79
83
|
|
80
84
|
def define_update_method(collection_name)
|
@@ -100,7 +104,8 @@ module ActiveRecord
|
|
100
104
|
instance_variable_set "@hmwds_temp_#{collection_name}", nil
|
101
105
|
end
|
102
106
|
end
|
103
|
-
|
107
|
+
alias_method(:"reload_without_deferred_save_for_#{collection_name}", :reload)
|
108
|
+
alias_method(:reload, :"reload_with_deferred_save_for_#{collection_name}")
|
104
109
|
end
|
105
110
|
end
|
106
111
|
end
|
data/spec/habtm_ar4_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'has_and_belongs_to_many_with_deferred_save'
|
3
3
|
|
4
|
-
if
|
5
|
-
describe 'ActiveRecord4 specials' do
|
4
|
+
if ar4_or_more?
|
5
|
+
describe 'ActiveRecord4/5 specials' do
|
6
6
|
before :all do
|
7
7
|
#ActiveRecord::Base.logger = Logger.new(STDOUT) # uncomment for debugging statements
|
8
8
|
@people = []
|
@@ -64,21 +64,21 @@ if ar4?
|
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'should preload with non-deferred association' do
|
67
|
-
rooms = Room.where(id: [@room1.id, @room2.id, @room3.id]).preload(:
|
67
|
+
rooms = Room.where(id: [@room1.id, @room2.id, @room3.id]).preload(:people_without_deferring)
|
68
68
|
rooms = rooms.to_a # execute original query, together with preloading the association
|
69
69
|
room1 = rooms.first
|
70
70
|
room2 = rooms.second
|
71
71
|
room3 = rooms.third
|
72
72
|
# association is autoloaded
|
73
|
-
expect(room1.
|
74
|
-
expect(room2.
|
75
|
-
expect(room3.
|
73
|
+
expect(room1.people_without_deferring.loaded?).to be true
|
74
|
+
expect(room2.people_without_deferring.loaded?).to be true
|
75
|
+
expect(room3.people_without_deferring.loaded?).to be true
|
76
76
|
|
77
77
|
expect(ActiveRecord::Base).not_to receive(:connection)
|
78
78
|
|
79
|
-
expect(room1.
|
80
|
-
expect(room2.
|
81
|
-
expect(room3.
|
79
|
+
expect(room1.people_without_deferring.map(&:name)).to match_array(%w(Miguel Rainer))
|
80
|
+
expect(room2.people_without_deferring.map(&:name)).to match_array(%w(Filbert Miguel))
|
81
|
+
expect(room3.people_without_deferring.map(&:name)).to match_array(%w())
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
@@ -113,14 +113,14 @@ describe 'has_and_belongs_to_many_with_deferred_save' do
|
|
113
113
|
end
|
114
114
|
|
115
115
|
it 'still lets you do find' do
|
116
|
-
if
|
117
|
-
expect(@room.
|
116
|
+
if ar4_or_more?
|
117
|
+
expect(@room.people_without_deferring.where(name: 'Filbert').first).to eq(@people[0])
|
118
118
|
expect(@room.people_without_deferred_save.where(name: 'Filbert').first).to eq(@people[0])
|
119
119
|
expect(@room.people.where(name: 'Filbert').first).to eq(@people[0])
|
120
120
|
else
|
121
|
-
expect(@room.
|
121
|
+
expect(@room.people_without_deferring. find(:first, conditions: { name: 'Filbert' })).to eq(@people[0])
|
122
122
|
expect(@room.people_without_deferred_save.find(:first, conditions: { name: 'Filbert' })).to eq(@people[0])
|
123
|
-
expect(@room.
|
123
|
+
expect(@room.people_without_deferring.first(conditions: { name: 'Filbert' })).to eq(@people[0])
|
124
124
|
expect(@room.people_without_deferred_save.first(conditions: { name: 'Filbert' })).to eq(@people[0])
|
125
125
|
|
126
126
|
expect(@room.people.find(:first, conditions: { name: 'Filbert' })).to eq(@people[0])
|
@@ -163,15 +163,31 @@ describe 'has_and_belongs_to_many_with_deferred_save' do
|
|
163
163
|
@room.people = [@people[0]]
|
164
164
|
@room.save
|
165
165
|
@room = Room.find(@room.id) # we don't want to let id and object setters interfere with each other
|
166
|
-
@room.
|
167
|
-
|
166
|
+
@room.people_without_deferring_ids << @people[1].id
|
167
|
+
|
168
|
+
if ar5_or_more?
|
169
|
+
# In Rails 5, ID array manipulation is taken into account, but only temporarily,
|
170
|
+
# therefore deferred_association doesn't mimic this behavior
|
171
|
+
expect(@room.people_without_deferring_ids).to eq([@people[0].id, @people[1].id])
|
172
|
+
else
|
173
|
+
# ID array manipulation is ignored
|
174
|
+
expect(@room.people_without_deferring_ids).to eq([@people[0].id])
|
175
|
+
end
|
168
176
|
|
169
177
|
expect(@room.person_ids.size).to eq(1)
|
170
178
|
@room.person_ids << @people[1].id
|
179
|
+
|
180
|
+
# deferred_association doesn't remember the additional ID, no matter, which AR version
|
181
|
+
# we are in
|
171
182
|
expect(@room.person_ids).to eq([@people[0].id])
|
172
183
|
expect(Room.find(@room.id).person_ids).to eq([@people[0].id])
|
173
184
|
expect(@room.save).to be true
|
174
|
-
|
185
|
+
|
186
|
+
# Original association didn't save the temporarily saved changes,
|
187
|
+
# the deferred association also looses the change on reload
|
188
|
+
@room = Room.find(@room.id)
|
189
|
+
expect(@room.people_without_deferring_ids).to eq([@people[0].id])
|
190
|
+
expect(@room.person_ids).to eq([@people[0].id])
|
175
191
|
end
|
176
192
|
|
177
193
|
it 'should work with id setters' do
|
@@ -84,7 +84,7 @@ describe 'has_many_with_deferred_save' do
|
|
84
84
|
|
85
85
|
it 'should defer association methods' do
|
86
86
|
expect(@room.chairs.first).to eq(@chair1)
|
87
|
-
if
|
87
|
+
if ar4_or_more?
|
88
88
|
expect(@room.chairs.where(name: 'First')).to eq([@chair1])
|
89
89
|
else
|
90
90
|
expect(@room.chairs.find(:all, conditions: { name: 'First' })).to eq([@chair1])
|
data/spec/models/room.rb
CHANGED
@@ -7,9 +7,13 @@ class Room < ActiveRecord::Base
|
|
7
7
|
before_save :diff_before_module
|
8
8
|
|
9
9
|
has_and_belongs_to_many_with_deferred_save :people, before_add: :before_adding_person
|
10
|
-
has_and_belongs_to_many :
|
10
|
+
has_and_belongs_to_many :people_without_deferring, class_name: 'Person'
|
11
11
|
has_and_belongs_to_many_with_deferred_save :doors
|
12
12
|
|
13
|
+
if ar5_or_more?
|
14
|
+
# without it, AR5 would throw a deprecation warning
|
15
|
+
attribute :tables
|
16
|
+
end
|
13
17
|
has_many_with_deferred_save :tables
|
14
18
|
has_many_with_deferred_save :chairs, through: :tables # TODO: test compatibility with through associations
|
15
19
|
|
data/spec/spec_helper.rb
CHANGED
@@ -18,8 +18,6 @@ ActiveRecord::Base.establish_connection(:sqlite3mem)
|
|
18
18
|
ActiveRecord::Migration.verbose = false
|
19
19
|
load(File.join(plugin_test_dir, 'db', 'schema.rb'))
|
20
20
|
|
21
|
-
Dir["#{plugin_test_dir}/models/*.rb"].each { |file| require file }
|
22
|
-
|
23
21
|
RSpec.configure do |config|
|
24
22
|
config.raise_errors_for_deprecations!
|
25
23
|
|
@@ -44,6 +42,12 @@ def ar2?
|
|
44
42
|
ActiveRecord::VERSION::STRING < '3'
|
45
43
|
end
|
46
44
|
|
47
|
-
def
|
45
|
+
def ar4_or_more?
|
48
46
|
ActiveRecord::VERSION::STRING >= '4'
|
49
47
|
end
|
48
|
+
|
49
|
+
def ar5_or_more?
|
50
|
+
ActiveRecord::VERSION::STRING >= '5'
|
51
|
+
end
|
52
|
+
|
53
|
+
Dir["#{plugin_test_dir}/models/*.rb"].each { |file| require file }
|
metadata
CHANGED
@@ -1,40 +1,40 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deferred_associations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Koerner
|
8
8
|
- Tyler Rick
|
9
9
|
- Alessio Caiazza
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2017-12-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
17
18
|
requirements:
|
18
19
|
- - ">="
|
19
20
|
- !ruby/object:Gem::Version
|
20
21
|
version: '0'
|
21
|
-
name: activerecord
|
22
|
-
prerelease: false
|
23
22
|
type: :runtime
|
23
|
+
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '0'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
|
+
name: rspec
|
30
31
|
requirement: !ruby/object:Gem::Requirement
|
31
32
|
requirements:
|
32
33
|
- - ">="
|
33
34
|
- !ruby/object:Gem::Version
|
34
35
|
version: '0'
|
35
|
-
name: rspec
|
36
|
-
prerelease: false
|
37
36
|
type: :development
|
37
|
+
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - ">="
|
@@ -76,7 +76,7 @@ homepage: http://github.com/MartinKoerner/deferred_associations
|
|
76
76
|
licenses:
|
77
77
|
- MIT
|
78
78
|
metadata: {}
|
79
|
-
post_install_message:
|
79
|
+
post_install_message:
|
80
80
|
rdoc_options: []
|
81
81
|
require_paths:
|
82
82
|
- lib
|
@@ -91,9 +91,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
|
-
rubyforge_project:
|
95
|
-
rubygems_version: 2.
|
96
|
-
signing_key:
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.5.1
|
96
|
+
signing_key:
|
97
97
|
specification_version: 3
|
98
98
|
summary: Makes ActiveRecord defer/postpone habtm or has_many associations
|
99
99
|
test_files: []
|