object_attorney 1.2.1 → 2.1.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 +8 -8
- data/db/migrate/20131205114000_create_users.rb +13 -0
- data/db/migrate/20131205114900_create_posts.rb +1 -1
- data/db/migrate/20131205114901_create_comments.rb +13 -0
- data/db/migrate/20131205114902_create_addresses.rb +13 -0
- data/lib/object_attorney/association_reflection.rb +52 -15
- data/lib/object_attorney/helpers.rb +4 -0
- data/lib/object_attorney/nested_objects.rb +88 -21
- data/lib/object_attorney/orm.rb +20 -10
- data/lib/object_attorney/orm_handlers/smooth_operator.rb +20 -15
- data/lib/object_attorney/reflection.rb +35 -0
- data/lib/object_attorney/version.rb +1 -1
- data/lib/object_attorney.rb +18 -10
- data/spec/object_attorney/bulk_post_form_spec.rb +52 -0
- data/spec/object_attorney/bulk_posts_allow_only_existing_form_spec.rb +37 -0
- data/spec/object_attorney/bulk_posts_allow_only_new_form_spec.rb +39 -0
- data/spec/object_attorney/bulk_posts_with_form_objects_form_spec.rb +91 -0
- data/spec/object_attorney/post_form_spec.rb +107 -41
- data/spec/object_attorney/post_with_comment_form_spec.rb +123 -0
- data/spec/object_attorney/post_with_comments_and_address_form_spec.rb +45 -0
- data/spec/object_attorney/user_form_spec.rb +61 -0
- data/spec/spec_helper.rb +15 -6
- data/spec/support/form_objects/bulk_posts_allow_only_existing_form.rb +19 -0
- data/spec/support/form_objects/bulk_posts_allow_only_new_form.rb +19 -0
- data/spec/support/form_objects/bulk_posts_form.rb +27 -0
- data/spec/support/form_objects/bulk_posts_with_form_objects_form.rb +27 -0
- data/spec/support/form_objects/comment_form.rb +11 -0
- data/spec/support/form_objects/post_form.rb +54 -0
- data/spec/support/form_objects/post_with_comment_form.rb +21 -0
- data/spec/support/form_objects/post_with_comments_and_address_form.rb +13 -0
- data/spec/support/form_objects/user_form.rb +11 -0
- data/spec/support/models/address.rb +5 -0
- data/spec/support/models/comment.rb +5 -0
- data/spec/support/models/post.rb +7 -1
- data/spec/support/models/user.rb +7 -0
- metadata +44 -19
- data/spec/object_attorney/bulk_posts_form_child_spec.rb +0 -191
- data/spec/object_attorney/bulk_posts_form_spec.rb +0 -178
- data/spec/object_attorney/post_form_child_spec.rb +0 -60
- data/spec/support/models/bulk_posts_form.rb +0 -21
- data/spec/support/models/bulk_posts_form_child.rb +0 -19
- data/spec/support/models/item.rb +0 -3
- data/spec/support/models/post_form.rb +0 -13
- data/spec/support/models/post_form_child.rb +0 -7
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZGE1NWUyMGQ1NzE4YjIyMmM0ZmJhN2YxYWJiZjczYmM1MTk5YzA1Mw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OTU5Y2FkZThiNDQ2Y2ZjZjhkYmIyNzhlN2ZlNmJhOWQ3OGZmOWU4ZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OTliNTEyNjU2ZjRhM2QwNjEyOTMyNmFiYzM4ZDJmYTViMmYwMzM0NDE4Y2Fj
|
10
|
+
ZGIzMDhhMjk1YjdjZjFjNWExYzU0NTRiZTdmOGM0NDJmZDk5OWExN2M2MWJk
|
11
|
+
MTI2MTdhNTIyMmExYTQ1MjVlYjY5NmVlZmI4ZGFmZTEwMzE3MDI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MDdiMmRjMjgxMDdkYmNiODU1MTMxYTA0ODU0M2JjZDVmMDYyYjNhNGFlMzFm
|
14
|
+
NDZmODY0NWUxNGYxN2Q2ZTA0NTY3YjBjODMxMTc4Y2IxM2UyNzViZWMyMjA1
|
15
|
+
ZGVjNzMyOWEzZGMyNjIzYjA1MzY0NzkzMWJmMGEzODRiMzE0OTU=
|
@@ -1,17 +1,54 @@
|
|
1
1
|
module ObjectAttorney
|
2
2
|
|
3
|
-
class AssociationReflection
|
4
|
-
attr_reader :
|
3
|
+
class AssociationReflection < Reflection
|
4
|
+
attr_reader :related_reflection, :macro
|
5
5
|
|
6
|
-
def initialize(association, options)
|
7
|
-
|
8
|
-
|
9
|
-
@name = association
|
6
|
+
def initialize(association, related_reflection, options)
|
7
|
+
super(association, options)
|
10
8
|
@macro = options[:macro] || macro_default(association)
|
11
|
-
@
|
12
|
-
|
9
|
+
@related_reflection = related_reflection
|
10
|
+
end
|
11
|
+
|
12
|
+
def primary_key
|
13
|
+
@primary_key ||= options[:primary_key] || :id
|
14
|
+
end
|
15
|
+
|
16
|
+
def foreign_key
|
17
|
+
@foreign_key ||= options[:foreign_key] || foreign_key_default
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_relational_keys(origin, destination)
|
21
|
+
if has_many? || has_one?
|
22
|
+
set_foreign_key(destination, primary_key_of(origin))
|
23
|
+
elsif belongs_to?
|
24
|
+
set_foreign_key(origin, primary_key_of(destination))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_foreign_key(object, id)
|
29
|
+
setter = "#{foreign_key}="
|
30
|
+
|
31
|
+
if object.respond_to?(setter)
|
32
|
+
object.send(setter, id)
|
33
|
+
elsif object.respond_to?("send_to_representative")
|
34
|
+
object.send_to_representative(setter, id)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def primary_key_of(object)
|
39
|
+
object.send(primary_key)
|
40
|
+
end
|
13
41
|
|
14
|
-
|
42
|
+
def has_many?
|
43
|
+
macro == :has_many
|
44
|
+
end
|
45
|
+
|
46
|
+
def has_one?
|
47
|
+
macro == :has_one
|
48
|
+
end
|
49
|
+
|
50
|
+
def belongs_to?
|
51
|
+
macro == :belongs_to
|
15
52
|
end
|
16
53
|
|
17
54
|
private ################################# private
|
@@ -20,12 +57,12 @@ module ObjectAttorney
|
|
20
57
|
Helpers.plural?(association) ? :has_many : :belongs_to
|
21
58
|
end
|
22
59
|
|
23
|
-
def
|
24
|
-
if
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
60
|
+
def foreign_key_default
|
61
|
+
if has_many? || has_one?
|
62
|
+
"#{related_reflection.single_name}_id"
|
63
|
+
elsif belongs_to?
|
64
|
+
"#{single_name}_id"
|
65
|
+
end.to_sym
|
29
66
|
end
|
30
67
|
|
31
68
|
end
|
@@ -1,10 +1,8 @@
|
|
1
|
+
require "object_attorney/association_reflection"
|
2
|
+
|
1
3
|
module ObjectAttorney
|
2
4
|
module NestedObjects
|
3
5
|
|
4
|
-
def nested_objects
|
5
|
-
self.class.nested_objects.map { |nested_object_sym| self.send(nested_object_sym) }.flatten
|
6
|
-
end
|
7
|
-
|
8
6
|
def mark_for_destruction
|
9
7
|
@marked_for_destruction = true
|
10
8
|
end
|
@@ -14,35 +12,54 @@ module ObjectAttorney
|
|
14
12
|
end
|
15
13
|
|
16
14
|
def mark_for_destruction_if_necessary(object, attributes)
|
17
|
-
return nil unless attributes.
|
15
|
+
return nil unless attributes.is_a?(Hash)
|
18
16
|
|
19
17
|
_destroy = attributes["_destroy"] || attributes[:_destroy]
|
20
18
|
|
21
19
|
object.mark_for_destruction if ["true", "1", true].include?(_destroy)
|
22
20
|
end
|
23
21
|
|
22
|
+
def nested_objects(macro = nil)
|
23
|
+
nested_objects_list = []
|
24
|
+
|
25
|
+
self.class.reflect_on_all_associations(macro).each do |reflection|
|
26
|
+
[*self.send(reflection.name)].each do |nested_object|
|
27
|
+
nested_objects_list << [reflection, nested_object]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
nested_objects_list
|
32
|
+
end
|
33
|
+
|
24
34
|
protected #################### PROTECTED METHODS DOWN BELOW ######################
|
25
35
|
|
26
|
-
def
|
27
|
-
nested_objects.map do |nested_object|
|
28
|
-
|
36
|
+
def save_or_destroy_nested_objects(save_method, association_macro)
|
37
|
+
nested_objects(association_macro).map do |reflection, nested_object|
|
38
|
+
|
39
|
+
populate_foreign_key(self, nested_object, reflection, :has_many)
|
40
|
+
populate_foreign_key(self, nested_object, reflection, :has_one)
|
41
|
+
|
42
|
+
saving_result = call_save_or_destroy(nested_object, save_method)
|
43
|
+
|
44
|
+
populate_foreign_key(self, nested_object, reflection, :belongs_to)
|
45
|
+
|
46
|
+
saving_result
|
47
|
+
|
29
48
|
end.all?
|
30
49
|
end
|
31
50
|
|
32
51
|
def validate_nested_objects
|
33
|
-
|
34
|
-
|
52
|
+
return true if nested_objects.map do |reflection, nested_object|
|
53
|
+
nested_object.marked_for_destruction? ? true : nested_object.valid?
|
54
|
+
end.all?
|
55
|
+
|
35
56
|
import_nested_objects_errors
|
36
57
|
false
|
37
58
|
end
|
38
59
|
|
39
60
|
def import_nested_objects_errors
|
40
|
-
|
41
|
-
|
42
|
-
[*self.send(nested_object_sym)].each do |nested_object|
|
43
|
-
nested_object.errors.full_messages.each { |message| self.errors.add(nested_object_sym, message) }
|
44
|
-
end
|
45
|
-
|
61
|
+
nested_objects.each do |reflection, nested_object|
|
62
|
+
nested_object.errors.full_messages.each { |message| self.errors.add(reflection.name, message) }
|
46
63
|
end
|
47
64
|
end
|
48
65
|
|
@@ -54,6 +71,12 @@ module ObjectAttorney
|
|
54
71
|
|
55
72
|
private #################### PRIVATE METHODS DOWN BELOW ######################
|
56
73
|
|
74
|
+
def populate_foreign_key(origin, destination, reflection, macro)
|
75
|
+
return nil if represented_object.blank? || check_if_marked_for_destruction?(destination) || reflection.macro != macro
|
76
|
+
|
77
|
+
reflection.set_relational_keys(origin, destination)
|
78
|
+
end
|
79
|
+
|
57
80
|
def self.included(base)
|
58
81
|
base.extend(ClassMethods)
|
59
82
|
|
@@ -93,7 +116,7 @@ module ObjectAttorney
|
|
93
116
|
end
|
94
117
|
|
95
118
|
def update_existing_nested_objects(existing_and_new_nested_objects, nested_object_name)
|
96
|
-
|
119
|
+
send("existing_#{nested_object_name}").each do |existing_nested_object|
|
97
120
|
attributes = get_attributes_for_existing(nested_object_name, existing_nested_object)
|
98
121
|
|
99
122
|
mark_for_destruction_if_necessary(existing_nested_object, attributes)
|
@@ -108,21 +131,60 @@ module ObjectAttorney
|
|
108
131
|
next if attributes["id"].present? || attributes[:id].present?
|
109
132
|
|
110
133
|
new_nested_object = send("build_#{nested_object_name.to_s.singularize}", attributes_without_destroy(attributes))
|
111
|
-
|
134
|
+
next unless new_nested_object
|
112
135
|
|
136
|
+
mark_for_destruction_if_necessary(new_nested_object, attributes)
|
113
137
|
existing_and_new_nested_objects << new_nested_object
|
114
138
|
end
|
115
139
|
end
|
116
140
|
|
141
|
+
def build_nested_object(nested_object_name, attributes = {})
|
142
|
+
reflection = self.class.reflect_on_association(nested_object_name)
|
143
|
+
|
144
|
+
new_nested_object = reflection.klass.new(attributes)
|
145
|
+
|
146
|
+
populate_foreign_key(self, new_nested_object, reflection, :has_many)
|
147
|
+
|
148
|
+
new_nested_object
|
149
|
+
end
|
150
|
+
|
151
|
+
def existing_nested_objects(nested_object_name)
|
152
|
+
nested_association_klass = self.class.reflect_on_association(nested_object_name).klass
|
153
|
+
|
154
|
+
existing_list = represented_object.blank? ? nested_association_klass.all : (represented_object.send(nested_object_name) || [])
|
155
|
+
|
156
|
+
if represented_object.present? && nested_association_klass != self.class.represented_object_class.reflect_on_association(nested_object_name).klass
|
157
|
+
existing_list = existing_list.map { |existing_nested_object| nested_association_klass.new({}, existing_nested_object) }
|
158
|
+
end
|
159
|
+
|
160
|
+
existing_list
|
161
|
+
end
|
162
|
+
|
117
163
|
module ClassMethods
|
118
164
|
|
165
|
+
def has_many(nested_object_name, options = {})
|
166
|
+
_accepts_nested_objects_overwrite_macro(nested_object_name, options, :has_many)
|
167
|
+
end
|
168
|
+
|
169
|
+
def has_one(nested_object_name, options = {})
|
170
|
+
_accepts_nested_objects_overwrite_macro(nested_object_name, options, :has_one)
|
171
|
+
end
|
172
|
+
|
173
|
+
def belongs_to(nested_object_name, options = {})
|
174
|
+
_accepts_nested_objects_overwrite_macro(nested_object_name, options, :belongs_to)
|
175
|
+
end
|
176
|
+
|
119
177
|
def accepts_nested_objects(nested_object_name, options = {})
|
120
|
-
reflection = AssociationReflection.new(nested_object_name, options)
|
178
|
+
reflection = AssociationReflection.new(nested_object_name, represented_object_reflection, options)
|
179
|
+
|
121
180
|
self.instance_variable_set("@#{nested_object_name}_reflection", reflection)
|
122
181
|
self.instance_variable_set("@association_reflections", association_reflections | [reflection])
|
123
182
|
|
124
183
|
self.send(:attr_accessor, "#{nested_object_name}_attributes".to_sym)
|
184
|
+
|
125
185
|
define_method(nested_object_name) { nested_getter(nested_object_name) }
|
186
|
+
define_method("build_#{reflection.single_name}") { |attributes = {}, nested_object = nil| build_nested_object(nested_object_name, attributes) }
|
187
|
+
define_method("existing_#{nested_object_name}") { existing_nested_objects(nested_object_name) }
|
126
188
|
end
|
127
189
|
|
128
190
|
def association_reflections
|
@@ -137,8 +199,13 @@ module ObjectAttorney
|
|
137
199
|
macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
|
138
200
|
end
|
139
201
|
|
140
|
-
|
141
|
-
|
202
|
+
|
203
|
+
private ############################### PRIVATE METHODS ###########################
|
204
|
+
|
205
|
+
def _accepts_nested_objects_overwrite_macro(nested_object_name, options, macro)
|
206
|
+
default_options = { macro: macro }
|
207
|
+
options = options.is_a?(Hash) ? options.merge(default_options) : default_options
|
208
|
+
accepts_nested_objects(nested_object_name, options)
|
142
209
|
end
|
143
210
|
|
144
211
|
end
|
data/lib/object_attorney/orm.rb
CHANGED
@@ -26,15 +26,15 @@ module ObjectAttorney
|
|
26
26
|
|
27
27
|
def destroy
|
28
28
|
return true if represented_object.blank?
|
29
|
-
|
29
|
+
represented_object.destroy
|
30
30
|
end
|
31
31
|
|
32
32
|
def call_save_or_destroy(object, save_method)
|
33
33
|
if object == self
|
34
|
-
represented_object.present? ?
|
34
|
+
represented_object.present? ? represented_object.send(save_method) : true
|
35
35
|
else
|
36
36
|
save_method = :destroy if check_if_marked_for_destruction?(object)
|
37
|
-
|
37
|
+
object.send(save_method)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -48,15 +48,29 @@ module ObjectAttorney
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def submit(save_method)
|
51
|
-
save_result =
|
52
|
-
save_result =
|
51
|
+
save_result = save_or_destroy_nested_objects(save_method, :belongs_to)
|
52
|
+
save_result = save_or_destroy_represented_object(save_method) if save_result
|
53
|
+
save_result = save_or_destroy_nested_objects(save_method, :has_many) if save_result
|
54
|
+
save_result = save_or_destroy_nested_objects(save_method, :has_one) if save_result
|
53
55
|
save_result
|
54
56
|
end
|
55
57
|
|
56
|
-
def
|
58
|
+
def save_or_destroy_represented_object(save_method)
|
57
59
|
return true if represented_object.blank?
|
58
60
|
call_save_or_destroy(represented_object, save_method)
|
59
61
|
end
|
62
|
+
|
63
|
+
def self.included(base)
|
64
|
+
base.extend(ClassMethods)
|
65
|
+
end
|
66
|
+
|
67
|
+
module ClassMethods
|
68
|
+
|
69
|
+
def all(*args)
|
70
|
+
represented_object_class.all(*args).map { |represented_object| self.new({}, represented_object) }
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
60
74
|
|
61
75
|
private #################### PRIVATE METHODS DOWN BELOW ######################
|
62
76
|
|
@@ -64,9 +78,5 @@ module ObjectAttorney
|
|
64
78
|
object.respond_to?(:marked_for_destruction?) ? object.marked_for_destruction? : false
|
65
79
|
end
|
66
80
|
|
67
|
-
def evoke_method_on_object(object, method)
|
68
|
-
object.send(method)
|
69
|
-
end
|
70
|
-
|
71
81
|
end
|
72
82
|
end
|
@@ -16,15 +16,15 @@ module ObjectAttorney
|
|
16
16
|
|
17
17
|
def destroy(options = {})
|
18
18
|
return true if represented_object.blank?
|
19
|
-
|
19
|
+
represented_object.destroy(options).ok?
|
20
20
|
end
|
21
21
|
|
22
22
|
def call_save_or_destroy(object, save_method, options = {})
|
23
23
|
if object == self || object == represented_object
|
24
|
-
represented_object.present? ?
|
24
|
+
represented_object.present? ? represented_object.send(save_method, options).ok? : true
|
25
25
|
else
|
26
26
|
save_method = :destroy if check_if_marked_for_destruction?(object)
|
27
|
-
|
27
|
+
object.send(save_method, options).ok?
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -35,26 +35,31 @@ module ObjectAttorney
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def submit(save_method, options = {})
|
38
|
-
save_result =
|
39
|
-
save_result =
|
38
|
+
save_result = save_or_destroy_nested_objects(save_method, :belongs_to, options)
|
39
|
+
save_result = save_or_destroy_represented_object(save_method, options) if save_result
|
40
|
+
save_result = save_or_destroy_nested_objects(save_method, :has_many, options) if save_result
|
41
|
+
save_result = save_or_destroy_nested_objects(save_method, :has_one, options) if save_result
|
40
42
|
save_result
|
41
43
|
end
|
42
44
|
|
43
|
-
def
|
45
|
+
def save_or_destroy_represented_object(save_method, options = {})
|
44
46
|
return true if represented_object.blank?
|
45
|
-
call_save_or_destroy(represented_object, save_method, options)
|
47
|
+
call_save_or_destroy(represented_object, save_method, options)
|
46
48
|
end
|
49
|
+
|
50
|
+
def save_or_destroy_nested_objects(save_method, association_macro, options = {})
|
51
|
+
nested_objects(association_macro).map do |reflection, nested_object|
|
52
|
+
|
53
|
+
populate_foreign_key(self, nested_object, reflection, :has_many)
|
54
|
+
populate_foreign_key(self, nested_object, reflection, :has_one)
|
47
55
|
|
48
|
-
|
49
|
-
nested_objects.map do |nested_object|
|
50
|
-
call_save_or_destroy(nested_object, save_method, options).ok?
|
51
|
-
end.all?
|
52
|
-
end
|
56
|
+
saving_result = call_save_or_destroy(nested_object, save_method, options)
|
53
57
|
|
54
|
-
|
58
|
+
populate_foreign_key(nested_object, self, reflection, :belongs_to)
|
55
59
|
|
56
|
-
|
57
|
-
|
60
|
+
saving_result
|
61
|
+
|
62
|
+
end.all?
|
58
63
|
end
|
59
64
|
|
60
65
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ObjectAttorney
|
2
|
+
|
3
|
+
class Reflection
|
4
|
+
attr_reader :name, :klass, :options
|
5
|
+
|
6
|
+
def initialize(class_name, options)
|
7
|
+
options = options.is_a?(Hash) ? options : {}
|
8
|
+
|
9
|
+
@name, @options = class_name, options
|
10
|
+
|
11
|
+
@klass = options[:class_name] || klass_default(@name)
|
12
|
+
@klass = @klass.constantize if @klass.is_a?(String)
|
13
|
+
end
|
14
|
+
|
15
|
+
def single_name
|
16
|
+
@single_name ||= options[:single_name] || name.to_s.singularize
|
17
|
+
end
|
18
|
+
|
19
|
+
def plural_name
|
20
|
+
@plural_name ||= options[:plural_name] || name.to_s.pluralize
|
21
|
+
end
|
22
|
+
|
23
|
+
private ################################# private
|
24
|
+
|
25
|
+
def klass_default(class_name)
|
26
|
+
if Helpers.plural?(class_name)
|
27
|
+
class_name.to_s.singularize.camelize
|
28
|
+
else
|
29
|
+
class_name.to_s.camelize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/object_attorney.rb
CHANGED
@@ -1,29 +1,26 @@
|
|
1
1
|
require "object_attorney/version"
|
2
2
|
require "object_attorney/helpers"
|
3
|
-
require "object_attorney/
|
3
|
+
require "object_attorney/reflection"
|
4
4
|
require "object_attorney/nested_objects"
|
5
5
|
require "object_attorney/orm"
|
6
6
|
require 'active_record'
|
7
7
|
|
8
8
|
module ObjectAttorney
|
9
9
|
|
10
|
-
def initialize(attributes = {}, object = nil
|
11
|
-
if !attributes.
|
10
|
+
def initialize(attributes = {}, object = nil)
|
11
|
+
if !attributes.is_a?(Hash) && object.blank?
|
12
12
|
object = attributes
|
13
13
|
attributes = nil
|
14
14
|
end
|
15
15
|
|
16
16
|
attributes = {} if attributes.blank?
|
17
17
|
|
18
|
-
if !attributes.include?("id") && object.kind_of?(String)
|
19
|
-
attributes["id"] = object
|
20
|
-
object = nil
|
21
|
-
end
|
22
|
-
|
23
18
|
@represented_object = object if object.present?
|
24
19
|
|
25
20
|
assign_attributes attributes
|
26
21
|
mark_for_destruction_if_necessary(self, attributes)
|
22
|
+
|
23
|
+
init(attributes)
|
27
24
|
end
|
28
25
|
|
29
26
|
def assign_attributes(attributes = {})
|
@@ -38,10 +35,17 @@ module ObjectAttorney
|
|
38
35
|
respond_to?(attribute) ? send(attribute) : nil
|
39
36
|
end
|
40
37
|
|
38
|
+
def send_to_representative(method_name, *args)
|
39
|
+
return false if represented_object.blank?
|
40
|
+
|
41
|
+
represented_object.send(method_name, *args)
|
42
|
+
end
|
43
|
+
|
41
44
|
protected #################### PROTECTED METHODS DOWN BELOW ######################
|
42
45
|
|
46
|
+
def init(attributes); end
|
47
|
+
|
43
48
|
def allowed_attribute(attribute)
|
44
|
-
attribute = attribute.to_s
|
45
49
|
respond_to?("#{attribute}=")
|
46
50
|
end
|
47
51
|
|
@@ -86,9 +90,13 @@ module ObjectAttorney
|
|
86
90
|
module ClassMethods
|
87
91
|
|
88
92
|
def represents(represented_object_name, options = {})
|
89
|
-
self.instance_variable_set("@represented_object_reflection",
|
93
|
+
self.instance_variable_set("@represented_object_reflection", Reflection.new(represented_object_name, options))
|
90
94
|
|
91
95
|
define_method(represented_object_name) { represented_object }
|
96
|
+
|
97
|
+
if options.include?(:properties)
|
98
|
+
delegate_properties(*options[:properties], to: represented_object_name)
|
99
|
+
end
|
92
100
|
end
|
93
101
|
|
94
102
|
def represented_object_reflection
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
shared_examples "a BulkPostsForm" do
|
5
|
+
|
6
|
+
it "1. Creating multiple 'Post's, with a tabless model 'BulkPostsForm' has if it had 'accepts_nested_attributes_for :posts'" do
|
7
|
+
params = {
|
8
|
+
bulk_post: {
|
9
|
+
posts_attributes: {
|
10
|
+
"0" => { title: "My title1" },
|
11
|
+
"1" => { title: "My title2" }
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
described_class.new(params[:bulk_post]).save
|
17
|
+
|
18
|
+
Post.all.count.should == 2
|
19
|
+
end
|
20
|
+
|
21
|
+
it "2. Creating new 'Post', editing another and deleting yet another." do
|
22
|
+
params = {
|
23
|
+
bulk_post: {
|
24
|
+
posts_attributes: {
|
25
|
+
"0" => { title: "new post" },
|
26
|
+
"2" => { id: 1, title: 'altered post' },
|
27
|
+
"1" => { id: 2, title: 'to be destroyed', _destroy: true }
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
Post.create(title: "My title1")
|
33
|
+
Post.create(title: "My title2")
|
34
|
+
Post.all.count.should == 2
|
35
|
+
Post.first.title.should == 'My title1'
|
36
|
+
|
37
|
+
described_class.new(params[:bulk_post]).save
|
38
|
+
|
39
|
+
Post.all.count.should == 2
|
40
|
+
Post.find_by_id(1).title.should == 'altered post'
|
41
|
+
Post.find_by_id(3).title.should == 'new post'
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe BulkPostsForm::Base do
|
47
|
+
it_behaves_like 'a BulkPostsForm'
|
48
|
+
end
|
49
|
+
|
50
|
+
describe BulkPostsForm::Explicit do
|
51
|
+
it_behaves_like 'a BulkPostsForm'
|
52
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
shared_examples "a BulkPostsAllowOnlyExistingForm" do
|
4
|
+
|
5
|
+
it "1. Tabless model 'BulkPostsAllowOnlyNew' only accepts editings 'Post' requests and ignores new requests." do
|
6
|
+
params = {
|
7
|
+
bulk_post: {
|
8
|
+
posts_attributes: {
|
9
|
+
"0" => { title: "new post" },
|
10
|
+
"1" => { id: 1, title: 'altered post' },
|
11
|
+
"2" => { id: 2, title: '', _destroy: true }
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
Post.create(title: "My title1")
|
17
|
+
Post.create(title: "My title2")
|
18
|
+
Post.all.count.should == 2
|
19
|
+
Post.find_by_id(1).title.should == 'My title1'
|
20
|
+
Post.find_by_id(2).title.should == 'My title2'
|
21
|
+
|
22
|
+
buld_posts_form = described_class.new(params[:bulk_post])
|
23
|
+
buld_posts_form.save
|
24
|
+
|
25
|
+
Post.all.count.should == 1
|
26
|
+
Post.first.title.should == 'altered post'
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe BulkPostsAllowOnlyExistingForm::Base do
|
32
|
+
it_behaves_like 'a BulkPostsAllowOnlyExistingForm'
|
33
|
+
end
|
34
|
+
|
35
|
+
describe BulkPostsAllowOnlyExistingForm::Explicit do
|
36
|
+
it_behaves_like 'a BulkPostsAllowOnlyExistingForm'
|
37
|
+
end
|