object_attorney 1.2.1 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|