embeds_many 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba71f51a1cc397e9552e7df72bd48f850f6b94f1
4
- data.tar.gz: d2a3a9e1d58f919d9151203c1a742f2cb30046be
3
+ metadata.gz: 3283d364282e4492da35bb5ab7ceb436641cebc1
4
+ data.tar.gz: e3b66d7c419d5c3ddd44c3d190a6d96b5ef74757
5
5
  SHA512:
6
- metadata.gz: 6f28e15a662b00e961dd31a3fc2cd3dafc0e02d4542c7f70244d6338dac273122e518de8a15098f1e63ba2f1230fc15c6d0a3baa91f5df8434310c2c3c04babb
7
- data.tar.gz: d348e086153200946b6e644ca9c047c1f2784f7770ecf9a0361b3ce68061638ef4416351b09ed145b07dd66d7e3f9ef0d7712b7ceeb0b054ffaff9711d3cba1b
6
+ metadata.gz: deca54390c5ed088b1150c68563c3116809161022f8f608aebba17d8cae0b6c96668be0f5581f3e07f0104812d0cfc10e8d18c7008518cbf4e8f82ac9b3ba759
7
+ data.tar.gz: 30904b474ae33b80e9aa54f5e431bea1c8cacea9af7f3100950df920411d92601251d38e669e7d9818ce7e1b719a4ce3ef912dfcadcadadff968936a9783ce5c
@@ -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.
@@ -10,6 +10,8 @@ module EmbedsMany
10
10
  instance_variable_set("@#{field}_collection", ChildrenCollection.new(self, field, child_klass))
11
11
  end
12
12
 
13
+ before_save { |parent| parent.send(field).before_parent_save }
14
+
13
15
  child_klass.class_eval(&block) if block
14
16
  end
15
17
  end
@@ -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
- if parent.save
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 save_new_record!
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
- if parent.save
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
- # tell rails the field will change
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.save
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
- attrs && @child_klass.new(attrs.merge(parent: @obj))
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
@@ -1,3 +1,3 @@
1
1
  module EmbedsMany
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -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
- it "should be able to update record" do
51
- tag = user.tags.create(name: 'bug', color: 'red')
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
- user.reload.tags.any? {|t| t.name == 'bug'}.should be_true
103
+ it "should not auto save invalid tag on parent save" do
104
+ tag = user.tags.create(name: 'bug', color: 'red')
54
105
 
55
- tag.update(color: 'yellow').should be_true
106
+ tag.color = 'yellow'
107
+ tag.name = ''
56
108
 
57
- user.reload.tags.any? {|t| t.color == 'yellow'}.should be_true
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
- it "should be able to destroy" do
61
- tag = user.tags.create(name: 'bug', color: 'red')
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
- tag.destroy.should be_true
128
+ user.update(name: 'liufengyun')
64
129
 
65
- user.reload.tags.any? {|t| t.name == 'bug'}.should be_false
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.0
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-03-29 00:00:00.000000000 Z
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.0.3
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