deferred_associations 0.5.7 → 0.5.8
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/CHANGELOG +4 -0
- data/Readme.markdown +3 -3
- data/VERSION +1 -1
- data/deferred_associations.gemspec +41 -44
- data/lib/array_to_association_wrapper.rb +68 -67
- data/lib/has_and_belongs_to_many_with_deferred_save.rb +34 -53
- data/lib/has_many_with_deferred_save.rb +107 -113
- data/spec/db/schema.rb +20 -22
- data/spec/habtm_ar4_spec.rb +85 -0
- data/spec/has_and_belongs_to_many_with_deferred_save_spec.rb +125 -128
- data/spec/has_many_with_deferred_save_spec.rb +103 -104
- data/spec/models/chair.rb +5 -3
- data/spec/models/door.rb +2 -0
- data/spec/models/person.rb +5 -3
- data/spec/models/room.rb +8 -9
- data/spec/models/table.rb +6 -4
- data/spec/spec_helper.rb +14 -12
- metadata +6 -5
- data/Rakefile +0 -27
@@ -1,104 +1,103 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'has_many_with_deferred_save' do
|
4
|
-
|
5
|
-
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@room.tables
|
15
|
-
@room.tables
|
16
|
-
|
17
|
-
@room.
|
18
|
-
@room.
|
19
|
-
@room.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@room.table_ids
|
36
|
-
@room.table_ids
|
37
|
-
|
38
|
-
@room.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
@room.tables
|
53
|
-
@room.tables
|
54
|
-
|
55
|
-
@room.
|
56
|
-
|
57
|
-
@room.tables
|
58
|
-
|
59
|
-
@room.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
@room.tables
|
65
|
-
@room.
|
66
|
-
@room.
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
@room.
|
79
|
-
@room.
|
80
|
-
@room.
|
81
|
-
@room.
|
82
|
-
@room.
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'has_many_with_deferred_save' do
|
4
|
+
before :each do
|
5
|
+
@room = Room.create(maximum_occupancy: 2)
|
6
|
+
@table1 = Table.create(room_id: @room.id)
|
7
|
+
@table2 = Table.create
|
8
|
+
@chair1 = Chair.create(table_id: @table1.id, name: 'First')
|
9
|
+
@chair2 = Chair.create(table_id: @table2.id, name: 'Second')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should work with tables obj setter/getter' do
|
13
|
+
expect(@room.tables).to eq [@table1]
|
14
|
+
@room.tables = [@table1, @table2]
|
15
|
+
expect(Room.find(@room.id).tables).to eq([@table1]) # not saved yet
|
16
|
+
expect(@room.tables).to eq([@table1, @table2])
|
17
|
+
expect(@room.table_ids).to eq([@table1.id, @table2.id])
|
18
|
+
expect(@room.save).to be true
|
19
|
+
expect(Room.find(@room.id).tables).to eq([@table1, @table2])
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should work with tables obj setter/getter, used twice' do
|
23
|
+
expect(@room.tables).to eq([@table1])
|
24
|
+
@room.tables = [@table1]
|
25
|
+
@room.tables = [@table1, @table2]
|
26
|
+
expect(Room.find(@room.id).tables).to eq([@table1]) # not saved yet
|
27
|
+
expect(@room.table_ids).to eq([@table1.id, @table2.id])
|
28
|
+
expect(@room.tables).to eq([@table1, @table2])
|
29
|
+
expect(@room.save).to be true
|
30
|
+
expect(Room.find(@room.id).tables).to eq([@table1, @table2])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should work with tables id setter/getter' do
|
34
|
+
expect(@room.table_ids).to eq([@table1.id])
|
35
|
+
@room.table_ids = [@table1.id, @table2.id]
|
36
|
+
expect(Room.find(@room.id).table_ids).to eq([@table1.id]) # not saved yet
|
37
|
+
expect(@room.save).to be true
|
38
|
+
expect(Room.find(@room.id).table_ids).to eq([@table1.id, @table2.id])
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should work with tables id setter/getter, used twice' do
|
42
|
+
expect(@room.table_ids).to eq([@table1.id])
|
43
|
+
@room.table_ids = [@table1.id]
|
44
|
+
@room.table_ids = [@table1.id, @table2.id]
|
45
|
+
expect(Room.find(@room.id).table_ids).to eq([@table1.id]) # not saved yet
|
46
|
+
expect(@room.save).to be true
|
47
|
+
expect(Room.find(@room.id).table_ids).to eq([@table1.id, @table2.id])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should work with array methods' do
|
51
|
+
expect(@room.tables).to eq([@table1])
|
52
|
+
@room.tables << @table2
|
53
|
+
expect(Room.find(@room.id).tables).to eq([@table1]) # not saved yet
|
54
|
+
expect(@room.save).to be true
|
55
|
+
expect(Room.find(@room.id).tables).to eq([@table1, @table2])
|
56
|
+
@room.tables -= [@table1]
|
57
|
+
expect(Room.find(@room.id).tables).to eq([@table1, @table2])
|
58
|
+
expect(@room.save).to be true
|
59
|
+
expect(Room.find(@room.id).tables).to eq([@table2])
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should reload temporary objects' do
|
63
|
+
@room.tables << @table2
|
64
|
+
expect(@room.tables).to eq([@table1, @table2])
|
65
|
+
@room.reload
|
66
|
+
expect(@room.tables).to eq([@table1])
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should be dumpable with Marshal' do
|
70
|
+
expect { Marshal.dump(@room.tables) }.not_to raise_exception
|
71
|
+
expect { Marshal.dump(Room.new.tables) }.not_to raise_exception
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'with through option' do
|
75
|
+
it 'should have a correct list' do
|
76
|
+
# TODO: these testcases need to be improved
|
77
|
+
expect(@room.chairs).to eq([@chair1]) # through table1
|
78
|
+
@room.tables << @table2
|
79
|
+
expect(@room.save).to be true
|
80
|
+
expect(@room.chairs).to eq([@chair1]) # association doesn't reload itself
|
81
|
+
@room.reload
|
82
|
+
expect(@room.chairs).to eq([@chair1, @chair2])
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should defer association methods' do
|
86
|
+
expect(@room.chairs.first).to eq(@chair1)
|
87
|
+
if ar4?
|
88
|
+
expect(@room.chairs.where(name: 'First')).to eq([@chair1])
|
89
|
+
else
|
90
|
+
expect(@room.chairs.find(:all, conditions: { name: 'First' })).to eq([@chair1])
|
91
|
+
end
|
92
|
+
|
93
|
+
expect do
|
94
|
+
@room.chairs.create(name: 'New one')
|
95
|
+
end.to raise_error(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should be dumpable with Marshal' do
|
99
|
+
expect { Marshal.dump(@room.chairs) }.not_to raise_exception
|
100
|
+
expect { Marshal.dump(Room.new.chairs) }.not_to raise_exception
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/spec/models/chair.rb
CHANGED
data/spec/models/door.rb
CHANGED
data/spec/models/person.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
class Person < ActiveRecord::Base
|
2
|
-
|
2
|
+
|
3
|
+
has_and_belongs_to_many_with_deferred_save :rooms, validate: true
|
3
4
|
|
4
5
|
attr_accessor :do_extra_validation
|
5
|
-
validate :extra_validation, :
|
6
|
+
validate :extra_validation, if: :do_extra_validation
|
6
7
|
|
7
8
|
def extra_validation
|
8
9
|
rooms.each do |room|
|
9
10
|
this_room_unsaved = rooms_without_deferred_save.include?(room) ? 0 : 1
|
10
11
|
if room.people.size + this_room_unsaved > room.maximum_occupancy
|
11
|
-
errors.add :rooms,
|
12
|
+
errors.add :rooms, 'This room has reached its maximum occupancy'
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
16
|
+
|
15
17
|
end
|
data/spec/models/room.rb
CHANGED
@@ -6,12 +6,12 @@ class Room < ActiveRecord::Base
|
|
6
6
|
|
7
7
|
before_save :diff_before_module
|
8
8
|
|
9
|
-
has_and_belongs_to_many_with_deferred_save :people, :
|
10
|
-
has_and_belongs_to_many :people2, :
|
9
|
+
has_and_belongs_to_many_with_deferred_save :people, before_add: :before_adding_person
|
10
|
+
has_and_belongs_to_many :people2, class_name: 'Person'
|
11
11
|
has_and_belongs_to_many_with_deferred_save :doors
|
12
12
|
|
13
13
|
has_many_with_deferred_save :tables
|
14
|
-
has_many_with_deferred_save :chairs, :
|
14
|
+
has_many_with_deferred_save :chairs, through: :tables # TODO: test compatibility with through associations
|
15
15
|
|
16
16
|
has_and_belongs_to_many_with_deferred_save :doors
|
17
17
|
has_many_with_deferred_save :tables
|
@@ -21,21 +21,19 @@ class Room < ActiveRecord::Base
|
|
21
21
|
validate :people_count
|
22
22
|
|
23
23
|
def people_count
|
24
|
-
if people.size > maximum_occupancy
|
25
|
-
errors.add :people, "This room has reached its maximum occupancy"
|
26
|
-
end
|
24
|
+
errors.add :people, 'This room has reached its maximum occupancy' if people.size > maximum_occupancy
|
27
25
|
end
|
28
26
|
|
29
27
|
# Just in case they try to bypass our new accessor and call people_without_deferred_save directly...
|
30
28
|
# (This should never be necessary; it is for demonstration purposes only...)
|
31
29
|
def before_adding_person(person)
|
32
|
-
if
|
33
|
-
raise
|
30
|
+
if people_without_deferred_save.size + [person].size > maximum_occupancy
|
31
|
+
raise 'There are too many people in this room'
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
def diff_before_module
|
38
|
-
#should detect the changes
|
36
|
+
# should detect the changes
|
39
37
|
self.bs_diff_before_module = (people.size - people_without_deferred_save.size) != 0
|
40
38
|
true
|
41
39
|
end
|
@@ -51,4 +49,5 @@ class Room < ActiveRecord::Base
|
|
51
49
|
self.bs_diff_method = (people.size - people_without_deferred_save.size) != 0
|
52
50
|
true
|
53
51
|
end
|
52
|
+
|
54
53
|
end
|
data/spec/models/table.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,27 +1,28 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
2
2
|
plugin_test_dir = File.dirname(__FILE__)
|
3
3
|
|
4
|
-
|
5
4
|
require 'active_record'
|
6
|
-
if ActiveRecord::VERSION::STRING >=
|
5
|
+
if ActiveRecord::VERSION::STRING >= '3'
|
7
6
|
require 'logger'
|
8
7
|
else
|
9
|
-
|
10
|
-
|
8
|
+
# Workaround for https://rails.lighthouseapp.com/projects/8994/tickets/2577-when-using-activerecordassociations-outside-of-rails-a-nameerror-is-thrown
|
9
|
+
ActiveRecord::ActiveRecordError
|
11
10
|
end
|
12
11
|
|
13
12
|
require plugin_test_dir + '/../init.rb'
|
14
13
|
|
15
|
-
ActiveRecord::Base.logger = Logger.new(plugin_test_dir +
|
14
|
+
ActiveRecord::Base.logger = Logger.new(plugin_test_dir + '/test.log')
|
16
15
|
|
17
|
-
ActiveRecord::Base.configurations = YAML
|
16
|
+
ActiveRecord::Base.configurations = YAML.load(IO.read(plugin_test_dir + '/db/database.yml'))
|
18
17
|
ActiveRecord::Base.establish_connection(:sqlite3mem)
|
19
18
|
ActiveRecord::Migration.verbose = false
|
20
|
-
load(File.join(plugin_test_dir,
|
19
|
+
load(File.join(plugin_test_dir, 'db', 'schema.rb'))
|
21
20
|
|
22
|
-
Dir["#{plugin_test_dir}/models/*.rb"].each {|file| require file }
|
21
|
+
Dir["#{plugin_test_dir}/models/*.rb"].each { |file| require file }
|
23
22
|
|
24
23
|
RSpec.configure do |config|
|
24
|
+
config.raise_errors_for_deprecations!
|
25
|
+
|
25
26
|
config.before do
|
26
27
|
end
|
27
28
|
end
|
@@ -29,19 +30,20 @@ end
|
|
29
30
|
class ActiveRecord::Base
|
30
31
|
|
31
32
|
# Compatibility method for AR 2.3.x and AR 3.2.x
|
32
|
-
def get_error
|
33
|
+
def get_error(attr)
|
33
34
|
if errors.respond_to?(:on)
|
34
35
|
errors.on(attr)
|
35
36
|
else
|
36
37
|
errors[attr].try(:first)
|
37
38
|
end
|
38
39
|
end
|
40
|
+
|
39
41
|
end
|
40
42
|
|
41
43
|
def ar2?
|
42
|
-
ActiveRecord::VERSION::STRING <
|
44
|
+
ActiveRecord::VERSION::STRING < '3'
|
43
45
|
end
|
44
46
|
|
45
47
|
def ar4?
|
46
|
-
ActiveRecord::VERSION::STRING >=
|
47
|
-
end
|
48
|
+
ActiveRecord::VERSION::STRING >= '4'
|
49
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deferred_associations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Koerner
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2016-03-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -52,7 +52,6 @@ extra_rdoc_files:
|
|
52
52
|
- Readme.markdown
|
53
53
|
files:
|
54
54
|
- CHANGELOG
|
55
|
-
- Rakefile
|
56
55
|
- Readme.markdown
|
57
56
|
- VERSION
|
58
57
|
- deferred_associations.gemspec
|
@@ -63,6 +62,7 @@ files:
|
|
63
62
|
- lib/has_many_with_deferred_save.rb
|
64
63
|
- spec/db/database.yml
|
65
64
|
- spec/db/schema.rb
|
65
|
+
- spec/habtm_ar4_spec.rb
|
66
66
|
- spec/has_and_belongs_to_many_with_deferred_save_spec.rb
|
67
67
|
- spec/has_many_with_deferred_save_spec.rb
|
68
68
|
- spec/models/chair.rb
|
@@ -72,7 +72,8 @@ files:
|
|
72
72
|
- spec/models/table.rb
|
73
73
|
- spec/spec_helper.rb
|
74
74
|
homepage: http://github.com/MartinKoerner/deferred_associations
|
75
|
-
licenses:
|
75
|
+
licenses:
|
76
|
+
- MIT
|
76
77
|
metadata: {}
|
77
78
|
post_install_message:
|
78
79
|
rdoc_options: []
|
@@ -90,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
91
|
version: '0'
|
91
92
|
requirements: []
|
92
93
|
rubyforge_project:
|
93
|
-
rubygems_version: 2.
|
94
|
+
rubygems_version: 2.5.1
|
94
95
|
signing_key:
|
95
96
|
specification_version: 3
|
96
97
|
summary: Makes ActiveRecord defer/postpone habtm or has_many associations
|
data/Rakefile
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
task :default do |t|
|
2
|
-
options = "--colour"
|
3
|
-
files = FileList['spec/**/*_spec.rb'].map{|f| f.sub(%r{^spec/},'') }
|
4
|
-
exit system("cd spec && spec #{options} #{files}") ? 0 : 1
|
5
|
-
end
|
6
|
-
|
7
|
-
begin
|
8
|
-
require 'jeweler'
|
9
|
-
project_name = 'deferred_associations'
|
10
|
-
Jeweler::Tasks.new do |gem|
|
11
|
-
gem.name = project_name
|
12
|
-
gem.summary = "Makes ActiveRecord defer/postpone habtm or has_many associations"
|
13
|
-
gem.description = "Makes ActiveRecord defer/postpone saving the records you add to an habtm (has_and_belongs_to_many) or has_many
|
14
|
-
association until you call model.save, allowing validation in the style of normal attributes. Additionally you
|
15
|
-
can check inside before_save filters, if the association was altered."
|
16
|
-
gem.homepage = "http://github.com/MartinKoerner/deferred_associations"
|
17
|
-
gem.email = "martin.koerner@objectfab.de"
|
18
|
-
gem.authors = ["Martin Koerner", "Tyler Rick", "Alessio Caiazza"]
|
19
|
-
gem.add_dependency('activerecord')
|
20
|
-
gem.add_development_dependency('rspec')
|
21
|
-
gem.files.exclude 'gemfiles/*', '.travis.yml'
|
22
|
-
end
|
23
|
-
|
24
|
-
Jeweler::GemcutterTasks.new
|
25
|
-
rescue LoadError
|
26
|
-
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
27
|
-
end
|