embeds_many 0.2.0 → 0.2.1
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/README.markdown +16 -0
- data/lib/embeds_many/base.rb +2 -0
- data/lib/embeds_many/child.rb +38 -10
- data/lib/embeds_many/child_collection.rb +24 -3
- data/lib/embeds_many/version.rb +1 -1
- data/spec/embeds_many/user_spec.rb +76 -9
- metadata +18 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3283d364282e4492da35bb5ab7ceb436641cebc1
|
4
|
+
data.tar.gz: e3b66d7c419d5c3ddd44c3d190a6d96b5ef74757
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: deca54390c5ed088b1150c68563c3116809161022f8f608aebba17d8cae0b6c96668be0f5581f3e07f0104812d0cfc10e8d18c7008518cbf4e8f82ac9b3ba759
|
7
|
+
data.tar.gz: 30904b474ae33b80e9aa54f5e431bea1c8cacea9af7f3100950df920411d92601251d38e669e7d9818ce7e1b719a4ce3ef912dfcadcadadff968936a9783ce5c
|
data/README.markdown
CHANGED
@@ -102,6 +102,22 @@ end
|
|
102
102
|
@tag.destroy
|
103
103
|
```
|
104
104
|
|
105
|
+
Embedded record are automatically saved on parent save. But invalid embedded records are not auto saved.
|
106
|
+
|
107
|
+
``` ruby
|
108
|
+
# auto save on parent save
|
109
|
+
user = User.new(name: 'test')
|
110
|
+
user.tags.new(tag_params)
|
111
|
+
|
112
|
+
user.save
|
113
|
+
|
114
|
+
# auto save on parent update
|
115
|
+
@tag = user.tags.find(params['id'])
|
116
|
+
@tag.color = 'red'
|
117
|
+
|
118
|
+
user.update(name: 'bob')
|
119
|
+
```
|
120
|
+
|
105
121
|
## Development
|
106
122
|
|
107
123
|
All pull requests are welcome.
|
data/lib/embeds_many/base.rb
CHANGED
data/lib/embeds_many/child.rb
CHANGED
@@ -22,7 +22,7 @@ module EmbedsMany
|
|
22
22
|
|
23
23
|
class UniquenessValidator < ActiveModel::EachValidator
|
24
24
|
def validate_each(record, attribute, value)
|
25
|
-
if record.exists_in_parent? {|item| item.key?(attribute.to_s) && item[attribute.to_s] == value && record.id.to_s != item['id'] }
|
25
|
+
if record.exists_in_parent? {|item| item.key?(attribute.to_s) && item[attribute.to_s] == value && record.id.to_s != item['id'].to_s }
|
26
26
|
record.errors.add attribute, "#{value} is already taken"
|
27
27
|
end
|
28
28
|
end
|
@@ -48,11 +48,15 @@ module EmbedsMany
|
|
48
48
|
def save
|
49
49
|
return false unless self.valid?
|
50
50
|
|
51
|
+
@operation_pending = true
|
52
|
+
|
51
53
|
if new_record?
|
52
54
|
save_new_record!
|
53
55
|
else
|
54
56
|
save_existing_record!
|
55
57
|
end
|
58
|
+
ensure
|
59
|
+
@operation_pending = false
|
56
60
|
end
|
57
61
|
|
58
62
|
def destroy
|
@@ -61,12 +65,18 @@ module EmbedsMany
|
|
61
65
|
|
62
66
|
parent.read_attribute(field_name).delete_if {|t| t['id'] == self.id}
|
63
67
|
|
64
|
-
|
68
|
+
@operation_pending = true
|
69
|
+
|
70
|
+
if parent.update(field_name => parent.read_attribute(field_name))
|
71
|
+
parent.send(field_name).child_destroyed(self)
|
72
|
+
|
65
73
|
true
|
66
74
|
else
|
67
75
|
parent.send "#{field_name}=", parent.send("#{field_name}_was")
|
68
76
|
false
|
69
77
|
end
|
78
|
+
ensure
|
79
|
+
@operation_pending = false
|
70
80
|
end
|
71
81
|
|
72
82
|
def update(attrs)
|
@@ -83,17 +93,39 @@ module EmbedsMany
|
|
83
93
|
parent.read_attribute(field_name).any? &block
|
84
94
|
end
|
85
95
|
|
96
|
+
def before_parent_save
|
97
|
+
return if @operation_pending or !self.valid?
|
98
|
+
|
99
|
+
if new_record?
|
100
|
+
fill_parent_field_new_record!
|
101
|
+
else
|
102
|
+
fill_parent_field_existing_record!
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
86
106
|
private
|
87
107
|
|
88
|
-
def
|
108
|
+
def fill_parent_field_new_record!
|
89
109
|
@attributes[:id] = generate_id!
|
90
110
|
|
91
111
|
# tell rails the field will change
|
92
112
|
parent.send "#{field_name}_will_change!"
|
93
113
|
|
94
114
|
parent.read_attribute(field_name) << @attributes.to_hash
|
115
|
+
end
|
95
116
|
|
96
|
-
|
117
|
+
def fill_parent_field_existing_record!
|
118
|
+
# tell rails the field will change
|
119
|
+
parent.send "#{field_name}_will_change!"
|
120
|
+
|
121
|
+
record = parent.read_attribute(field_name).detect {|t| t['id'].to_i == self.id.to_i }
|
122
|
+
record.merge!(@attributes)
|
123
|
+
end
|
124
|
+
|
125
|
+
def save_new_record!
|
126
|
+
fill_parent_field_new_record!
|
127
|
+
|
128
|
+
if parent.update(field_name => parent.read_attribute(field_name))
|
97
129
|
true
|
98
130
|
else
|
99
131
|
@attributes.id = nil
|
@@ -104,13 +136,9 @@ module EmbedsMany
|
|
104
136
|
end
|
105
137
|
|
106
138
|
def save_existing_record!
|
107
|
-
|
108
|
-
parent.send "#{field_name}_will_change!"
|
109
|
-
|
110
|
-
record = parent.read_attribute(field_name).detect {|t| t['id'].to_i == self.id.to_i }
|
111
|
-
record.merge!(@attributes)
|
139
|
+
fill_parent_field_existing_record!
|
112
140
|
|
113
|
-
if parent.
|
141
|
+
if parent.update(field_name => parent.read_attribute(field_name))
|
114
142
|
true
|
115
143
|
else
|
116
144
|
# restore old value
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module EmbedsMany
|
2
2
|
class ChildrenCollection
|
3
3
|
def new(attrs={})
|
4
|
-
@child_klass.new(attrs.merge(parent: @obj))
|
4
|
+
record = @child_klass.new(attrs.merge(parent: @obj))
|
5
|
+
@created_instances << record
|
6
|
+
|
7
|
+
record
|
5
8
|
end
|
6
9
|
|
7
10
|
def create(attrs={})
|
@@ -9,6 +12,8 @@ module EmbedsMany
|
|
9
12
|
|
10
13
|
record.save
|
11
14
|
|
15
|
+
@created_instances << record
|
16
|
+
|
12
17
|
record
|
13
18
|
end
|
14
19
|
|
@@ -16,12 +21,18 @@ module EmbedsMany
|
|
16
21
|
@obj = obj
|
17
22
|
@field = field
|
18
23
|
@child_klass = child_klass
|
24
|
+
@created_instances = []
|
19
25
|
end
|
20
26
|
|
21
27
|
def find(id)
|
22
28
|
attrs = @obj.read_attribute(@field).find {|child| child['id'].to_i == id.to_i }
|
23
29
|
|
24
|
-
|
30
|
+
if attrs
|
31
|
+
record = @child_klass.new(attrs.merge(parent: @obj))
|
32
|
+
@created_instances << record
|
33
|
+
|
34
|
+
record
|
35
|
+
end
|
25
36
|
end
|
26
37
|
|
27
38
|
# all records
|
@@ -31,9 +42,19 @@ module EmbedsMany
|
|
31
42
|
end
|
32
43
|
end
|
33
44
|
|
45
|
+
# called before parent save
|
46
|
+
def before_parent_save
|
47
|
+
@created_instances.map(&:before_parent_save)
|
48
|
+
end
|
49
|
+
|
50
|
+
# child destroyed
|
51
|
+
def child_destroyed(child)
|
52
|
+
@created_instances.delete(child)
|
53
|
+
end
|
54
|
+
|
34
55
|
# pass unhandled message to children array
|
35
56
|
def method_missing(symbol, *args, &block)
|
36
57
|
all.send(symbol, *args, &block)
|
37
58
|
end
|
38
59
|
end
|
39
|
-
end
|
60
|
+
end
|
data/lib/embeds_many/version.rb
CHANGED
@@ -44,25 +44,92 @@ describe User do
|
|
44
44
|
tag.save.should be_false
|
45
45
|
tag.errors[:color].should_not be_empty
|
46
46
|
end
|
47
|
+
|
48
|
+
it "should auto save new tags on parent update" do
|
49
|
+
tag = user.tags.new(name: 'bug', color: 'red')
|
50
|
+
|
51
|
+
user.update(name: 'liufengyun')
|
52
|
+
|
53
|
+
user.reload.tags.any? {|t| t.name == 'bug'}.should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should not auto save invalid new tags on parent update" do
|
57
|
+
tag = user.tags.new(name: 'bug')
|
58
|
+
|
59
|
+
user.save
|
60
|
+
|
61
|
+
user.reload.tags.any? {|t| t.name == 'bug'}.should be_false
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should auto save new tags on parent create" do
|
65
|
+
new_user = User.new(name: 'user')
|
66
|
+
tag = new_user.tags.new(name: 'bug', color: 'red')
|
67
|
+
|
68
|
+
new_user.save
|
69
|
+
|
70
|
+
new_user.reload.tags.any? {|t| t.name == 'bug'}.should be_true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should not auto save invalid new tags on parent create" do
|
74
|
+
new_user = User.new(name: 'user')
|
75
|
+
tag = new_user.tags.new(name: 'bug')
|
76
|
+
|
77
|
+
new_user.save
|
78
|
+
|
79
|
+
new_user.reload.tags.any? {|t| t.name == 'bug'}.should be_false
|
80
|
+
end
|
47
81
|
end
|
48
82
|
|
83
|
+
describe "update" do
|
84
|
+
it "should be able to update record" do
|
85
|
+
tag = user.tags.create(name: 'bug', color: 'red')
|
86
|
+
|
87
|
+
user.reload.tags.any? {|t| t.name == 'bug'}.should be_true
|
49
88
|
|
50
|
-
|
51
|
-
|
89
|
+
tag.update(color: 'yellow').should be_true
|
90
|
+
|
91
|
+
user.reload.tags.any? {|t| t.color == 'yellow'}.should be_true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should auto save tag on parent update" do
|
95
|
+
tag = user.tags.create(name: 'bug', color: 'red')
|
96
|
+
tag.color = 'yellow'
|
97
|
+
|
98
|
+
user.update(name: 'liufengyun')
|
99
|
+
|
100
|
+
user.reload.tags.any? {|t| t.color == 'yellow'}.should be_true
|
101
|
+
end
|
52
102
|
|
53
|
-
|
103
|
+
it "should not auto save invalid tag on parent save" do
|
104
|
+
tag = user.tags.create(name: 'bug', color: 'red')
|
54
105
|
|
55
|
-
|
106
|
+
tag.color = 'yellow'
|
107
|
+
tag.name = ''
|
56
108
|
|
57
|
-
|
109
|
+
user.update(name: 'liufengyun')
|
110
|
+
|
111
|
+
user.reload.tags.any? {|t| t.color == 'yellow'}.should be_false
|
112
|
+
end
|
58
113
|
end
|
59
114
|
|
60
|
-
|
61
|
-
|
115
|
+
describe "destroy" do
|
116
|
+
it "should be able to destroy" do
|
117
|
+
tag = user.tags.create(name: 'bug', color: 'red')
|
118
|
+
|
119
|
+
tag.destroy.should be_true
|
120
|
+
|
121
|
+
user.reload.tags.any? {|t| t.name == 'bug'}.should be_false
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should not be saved on parent save after destroy" do
|
125
|
+
tag = user.tags.create(name: 'bug', color: 'red')
|
126
|
+
tag.destroy
|
62
127
|
|
63
|
-
|
128
|
+
user.update(name: 'liufengyun')
|
64
129
|
|
65
|
-
|
130
|
+
user.reload.tags.any? {|t| t.color == 'yellow'}.should be_false
|
131
|
+
end
|
66
132
|
end
|
133
|
+
|
67
134
|
end
|
68
135
|
end
|
metadata
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embeds_many
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- liufengyun
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 4.0.4
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 4.0.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: database_cleaner
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: pg
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
description: EmbedsMany allows programmers to work with embedded records the same
|
@@ -88,9 +88,9 @@ executables: []
|
|
88
88
|
extensions: []
|
89
89
|
extra_rdoc_files: []
|
90
90
|
files:
|
91
|
-
- .gitignore
|
92
|
-
- .rspec
|
93
|
-
- .travis.yml
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".travis.yml"
|
94
94
|
- Gemfile
|
95
95
|
- LICENSE
|
96
96
|
- README.markdown
|
@@ -114,17 +114,17 @@ require_paths:
|
|
114
114
|
- lib
|
115
115
|
required_ruby_version: !ruby/object:Gem::Requirement
|
116
116
|
requirements:
|
117
|
-
- -
|
117
|
+
- - ">="
|
118
118
|
- !ruby/object:Gem::Version
|
119
119
|
version: '0'
|
120
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
requirements: []
|
126
126
|
rubyforge_project:
|
127
|
-
rubygems_version: 2.
|
127
|
+
rubygems_version: 2.2.2
|
128
128
|
signing_key:
|
129
129
|
specification_version: 4
|
130
130
|
summary: Embedded records based on the power of PostgreSQL's hstore and array
|