snusnu-dm-accepts_nested_attributes 0.0.6 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +13 -8
- data/Rakefile +2 -3
- data/TODO +5 -0
- data/lib/dm-accepts_nested_attributes.rb +7 -14
- data/lib/dm-accepts_nested_attributes/error_collecting.rb +35 -0
- data/lib/dm-accepts_nested_attributes/model.rb +132 -0
- data/lib/dm-accepts_nested_attributes/resource.rb +218 -29
- data/lib/dm-accepts_nested_attributes/save.rb +13 -0
- data/lib/dm-accepts_nested_attributes/transactional_save.rb +15 -0
- data/lib/dm-accepts_nested_attributes/version.rb +1 -1
- data/spec/fixtures/person.rb +8 -0
- data/spec/fixtures/profile.rb +9 -0
- data/spec/fixtures/project.rb +8 -0
- data/spec/fixtures/project_membership.rb +8 -0
- data/spec/fixtures/task.rb +9 -0
- data/spec/integration/belongs_to_spec.rb +10 -134
- data/spec/integration/has_1_spec.rb +9 -121
- data/spec/integration/has_n_spec.rb +10 -149
- data/spec/integration/has_n_through_spec.rb +10 -162
- data/spec/{shared → lib}/rspec_tmbundle_support.rb +1 -1
- data/spec/shared/belongs_to_spec.rb +127 -0
- data/spec/shared/has_1_spec.rb +103 -0
- data/spec/shared/has_n_spec.rb +114 -0
- data/spec/shared/has_n_through_spec.rb +139 -0
- data/spec/spec_helper.rb +12 -9
- data/spec/unit/accepts_nested_attributes_for_spec.rb +39 -118
- data/tasks/changelog.rb +18 -0
- data/tasks/spec.rb +0 -1
- metadata +19 -14
- data/lib/dm-accepts_nested_attributes/association_proxies.rb +0 -55
- data/lib/dm-accepts_nested_attributes/association_validation.rb +0 -49
- data/lib/dm-accepts_nested_attributes/nested_attributes.rb +0 -350
- data/spec/unit/resource_spec.rb +0 -174
data/Manifest.txt
CHANGED
@@ -7,25 +7,30 @@ Rakefile
|
|
7
7
|
TODO
|
8
8
|
CHANGELOG
|
9
9
|
lib/dm-accepts_nested_attributes.rb
|
10
|
-
lib/dm-accepts_nested_attributes/
|
11
|
-
lib/dm-accepts_nested_attributes/
|
12
|
-
lib/dm-accepts_nested_attributes/nested_attributes.rb
|
10
|
+
lib/dm-accepts_nested_attributes/error_collecting.rb
|
11
|
+
lib/dm-accepts_nested_attributes/model.rb
|
13
12
|
lib/dm-accepts_nested_attributes/resource.rb
|
13
|
+
lib/dm-accepts_nested_attributes/save.rb
|
14
|
+
lib/dm-accepts_nested_attributes/transactional_save.rb
|
14
15
|
lib/dm-accepts_nested_attributes/version.rb
|
16
|
+
spec/spec.opts
|
17
|
+
spec/spec_helper.rb
|
18
|
+
spec/lib/rspec_tmbundle_support.rb
|
15
19
|
spec/fixtures/person.rb
|
16
20
|
spec/fixtures/profile.rb
|
17
21
|
spec/fixtures/project.rb
|
18
22
|
spec/fixtures/project_membership.rb
|
19
23
|
spec/fixtures/task.rb
|
24
|
+
spec/shared/belongs_to_spec.rb
|
25
|
+
spec/shared/has_1_spec.rb
|
26
|
+
spec/shared/has_n_spec.rb
|
27
|
+
spec/shared/has_n_through_spec.rb
|
28
|
+
spec/unit/accepts_nested_attributes_for_spec.rb
|
20
29
|
spec/integration/belongs_to_spec.rb
|
21
30
|
spec/integration/has_1_spec.rb
|
22
31
|
spec/integration/has_n_spec.rb
|
23
32
|
spec/integration/has_n_through_spec.rb
|
24
|
-
|
25
|
-
spec/spec.opts
|
26
|
-
spec/spec_helper.rb
|
27
|
-
spec/unit/accepts_nested_attributes_for_spec.rb
|
28
|
-
spec/unit/resource_spec.rb
|
33
|
+
tasks/changelog.rb
|
29
34
|
tasks/gemspec.rb
|
30
35
|
tasks/hoe.rb
|
31
36
|
tasks/install.rb
|
data/Rakefile
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require 'rubygems'
|
3
2
|
require 'rake'
|
4
3
|
require 'rake/rdoctask'
|
5
4
|
|
@@ -16,8 +15,8 @@ GEM_NAME = "dm-accepts_nested_attributes"
|
|
16
15
|
GEM_VERSION = DataMapper::NestedAttributes::VERSION
|
17
16
|
|
18
17
|
GEM_DEPENDENCIES = [
|
19
|
-
["dm-core",
|
20
|
-
[
|
18
|
+
["dm-core", '>=0.10.0'],
|
19
|
+
["dm-validations", '>=0.10.0']
|
21
20
|
]
|
22
21
|
|
23
22
|
GEM_CLEAN = %w[ log pkg coverage ]
|
data/TODO
CHANGED
@@ -1,3 +1,8 @@
|
|
1
1
|
TODO
|
2
2
|
====
|
3
3
|
|
4
|
+
* add specs for :reject_if => :foo option, but think about _where_ first!
|
5
|
+
* think about supporting :reject_unless in addition to :reject_if
|
6
|
+
* think about generalizing :reject_if to not only work for new? resources
|
7
|
+
* think about :allow_destroy accepting the same parameters like :reject_if
|
8
|
+
(Symbol, String, #call)
|
@@ -1,20 +1,13 @@
|
|
1
|
-
# Needed to import datamapper and other gems
|
2
|
-
require 'rubygems'
|
3
1
|
require 'pathname'
|
4
|
-
|
5
|
-
# Add all external dependencies for the plugin here
|
6
|
-
gem 'dm-core', '>=0.9.11'
|
7
|
-
gem 'dm-validations', '>=0.9.11'
|
8
|
-
|
9
2
|
require 'dm-core'
|
10
|
-
require 'dm-validations'
|
11
3
|
|
12
|
-
# Require plugin-files
|
13
4
|
dir = Pathname(__FILE__).dirname.expand_path / 'dm-accepts_nested_attributes'
|
5
|
+
|
6
|
+
require dir / 'model'
|
7
|
+
#require dir / 'save'
|
14
8
|
require dir / 'resource'
|
15
|
-
require dir / 'association_proxies'
|
16
|
-
require dir / 'nested_attributes'
|
17
9
|
|
18
|
-
#
|
19
|
-
DataMapper::Model.append_extensions
|
20
|
-
DataMapper::
|
10
|
+
# Activate the plugin
|
11
|
+
DataMapper::Model.append_extensions(DataMapper::NestedAttributes::Model)
|
12
|
+
#DataMapper::Model.append_inclusions(DataMapper::NestedAttributes::Save)
|
13
|
+
DataMapper::Model.append_inclusions(DataMapper::NestedAttributes::CommonResourceSupport)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module NestedAttributes
|
3
|
+
|
4
|
+
module ValidationErrorCollecting
|
5
|
+
|
6
|
+
# collect errors on parent associations
|
7
|
+
def before_save_parent_association(association, context)
|
8
|
+
if association.respond_to?(:each)
|
9
|
+
association.each do |r|
|
10
|
+
unless r.valid?(context)
|
11
|
+
r.errors.each { |e| self.errors.add(:general, e) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
else
|
15
|
+
unless association.valid?(context)
|
16
|
+
association.errors.each { |e| self.errors.add(:general, e) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# collect errors on child associations
|
22
|
+
def before_save_child_association(association, context)
|
23
|
+
if association.respond_to?(:valid?)
|
24
|
+
unless association.valid?(context)
|
25
|
+
association.errors.each { |e| self.errors.add(:general, e) }
|
26
|
+
end
|
27
|
+
else
|
28
|
+
self.errors.add(:general, "child association is missing")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module NestedAttributes
|
3
|
+
|
4
|
+
##
|
5
|
+
# raised by accepts_nested_attributes_for
|
6
|
+
# if the passed options don't make sense
|
7
|
+
class InvalidOptions < ArgumentError; end
|
8
|
+
|
9
|
+
module Model
|
10
|
+
|
11
|
+
##
|
12
|
+
# Allows any association to accept nested attributes.
|
13
|
+
#
|
14
|
+
# @param association_name [Symbol, String]
|
15
|
+
# The name of the association that should accept nested attributes
|
16
|
+
#
|
17
|
+
# @param options [Hash, nil]
|
18
|
+
# List of resources to initialize the Collection with
|
19
|
+
#
|
20
|
+
# @option :reject_if [Symbol, String, #call]
|
21
|
+
# An instance method name or an object that respond_to?(:call), which
|
22
|
+
# stops a new record from being created, if it evaluates to true.
|
23
|
+
#
|
24
|
+
# @option :allow_destroy [true, false]
|
25
|
+
# If true, allow destroying the association via the generated writer
|
26
|
+
# If false, prevent destroying the association via the generated writer
|
27
|
+
# defaults to false
|
28
|
+
#
|
29
|
+
# @return nil
|
30
|
+
def accepts_nested_attributes_for(association_name, options = {})
|
31
|
+
|
32
|
+
# ----------------------------------------------------------------------------------
|
33
|
+
# try to fail as early as possible
|
34
|
+
# ----------------------------------------------------------------------------------
|
35
|
+
|
36
|
+
unless relationship = relationships(repository_name)[association_name]
|
37
|
+
raise(ArgumentError, "No relationship #{name.inspect} for #{self.name} in #{repository_name}")
|
38
|
+
end
|
39
|
+
|
40
|
+
# raise InvalidOptions if the given options don't make sense
|
41
|
+
assert_valid_options_for_nested_attributes(options)
|
42
|
+
|
43
|
+
# by default, nested attributes can't be destroyed
|
44
|
+
options = { :allow_destroy => false }.update(options)
|
45
|
+
|
46
|
+
# ----------------------------------------------------------------------------------
|
47
|
+
# should be safe to go from here
|
48
|
+
# ----------------------------------------------------------------------------------
|
49
|
+
|
50
|
+
options_for_nested_attributes[relationship] = options
|
51
|
+
|
52
|
+
include ::DataMapper::NestedAttributes::Resource
|
53
|
+
|
54
|
+
add_save_behavior
|
55
|
+
|
56
|
+
# TODO i wonder if this is the best place here?
|
57
|
+
# the transactional save behavior is definitely not needed for all resources,
|
58
|
+
# but it's necessary for resources that accept nested attributes
|
59
|
+
# FIXME this leads to weird "no such table" errors when specs are run
|
60
|
+
add_transactional_save_behavior # TODO if repository.adapter.supports_transactions?
|
61
|
+
|
62
|
+
# TODO make this do something
|
63
|
+
# it's only here now to remind me that this is probably the best place to put it
|
64
|
+
add_error_collection_behavior if DataMapper.const_defined?('Validate')
|
65
|
+
|
66
|
+
type = relationship.max > 1 ? :collection : :resource
|
67
|
+
|
68
|
+
define_method "#{association_name}_attributes" do
|
69
|
+
instance_variable_get("@#{association_name}_attributes")
|
70
|
+
end
|
71
|
+
|
72
|
+
define_method "#{association_name}_attributes=" do |attributes|
|
73
|
+
attributes = sanitize_nested_attributes(attributes)
|
74
|
+
instance_variable_set("@#{association_name}_attributes", attributes)
|
75
|
+
send("assign_nested_attributes_for_related_#{type}", relationship, attributes)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# The options given to the accepts_nested_attributes method
|
82
|
+
# They are guaranteed to be valid if they made it this far.
|
83
|
+
#
|
84
|
+
# @return [Hash] The options given to the accepts_nested_attributes method
|
85
|
+
# @see accepts_nested_attributes
|
86
|
+
def options_for_nested_attributes
|
87
|
+
@options_for_nested_attributes ||= {}
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def add_save_behavior
|
93
|
+
require Pathname(__FILE__).dirname.expand_path + 'save'
|
94
|
+
include ::DataMapper::NestedAttributes::Save
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_transactional_save_behavior
|
98
|
+
require Pathname(__FILE__).dirname.expand_path + 'transactional_save'
|
99
|
+
include ::DataMapper::NestedAttributes::TransactionalSave
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_error_collection_behavior
|
103
|
+
require Pathname(__FILE__).dirname.expand_path + 'error_collecting'
|
104
|
+
include ::DataMapper::NestedAttributes::ValidationErrorCollecting
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def assert_valid_options_for_nested_attributes(options)
|
109
|
+
|
110
|
+
assert_kind_of 'options', options, Hash
|
111
|
+
|
112
|
+
valid_options = [ :allow_destroy, :reject_if ]
|
113
|
+
|
114
|
+
unless options.all? { |k,v| valid_options.include?(k) }
|
115
|
+
raise InvalidOptions, 'options must be one of :allow_destroy or :reject_if'
|
116
|
+
end
|
117
|
+
|
118
|
+
guard = options[:reject_if]
|
119
|
+
if guard.is_a?(Symbol) || guard.is_a?(String)
|
120
|
+
msg = ":reject_if => #{guard.inspect}, but there is no instance method #{guard.inspect} in #{self.name}"
|
121
|
+
raise InvalidOptions, msg unless instance_methods.include?(options[:reject_if].to_s)
|
122
|
+
else
|
123
|
+
msg = ":reject_if must be a Symbol|String or respond_to?(:call) "
|
124
|
+
raise InvalidOptions, msg unless guard.nil? || guard.respond_to?(:call)
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -1,42 +1,231 @@
|
|
1
1
|
module DataMapper
|
2
|
-
module
|
3
|
-
|
4
|
-
# basic extract method refactorings to work around a bug in extlib
|
5
|
-
# see http://sick.snusnu.info/2009/04/29/extlibhook-breaks-if-hooked-method-is-redefined/
|
6
|
-
# maybe they are worth considering even when the bug in extlib (hopefully) gets fixed
|
2
|
+
module NestedAttributes
|
7
3
|
|
8
|
-
|
4
|
+
module Resource
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
##
|
7
|
+
# Can be used to remove ambiguities from the passed attributes.
|
8
|
+
# Consider a situation with a belongs_to association where both a valid value
|
9
|
+
# for the foreign_key attribute *and* nested_attributes for a new record are
|
10
|
+
# present (i.e. item_type_id and item_type_attributes are present).
|
11
|
+
# Also see http://is.gd/sz2d on the rails-core ml for a discussion on this.
|
12
|
+
# The basic idea is, that there should be a well defined behavior for what
|
13
|
+
# exactly happens when such a situation occurs. I'm currently in favor for
|
14
|
+
# using the foreign_key if it is present, but this probably needs more thinking.
|
15
|
+
# For now, this method basically is a no-op, but at least it provides a hook where
|
16
|
+
# everyone can perform it's own sanitization by overwriting this method.
|
17
|
+
#
|
18
|
+
# @return [Hash] The sanitized attributes
|
19
|
+
def sanitize_nested_attributes(attributes)
|
20
|
+
attributes # noop
|
17
21
|
end
|
18
22
|
|
19
|
-
|
23
|
+
private
|
24
|
+
|
25
|
+
# Attribute hash keys that should not be assigned as normal attributes.
|
26
|
+
# These hash keys are nested attributes implementation details.
|
27
|
+
UNASSIGNABLE_KEYS = [ :id, :_delete ]
|
28
|
+
|
29
|
+
|
30
|
+
##
|
31
|
+
# Assigns the given attributes to the resource association.
|
32
|
+
#
|
33
|
+
# If the given attributes include an <tt>:id</tt> that matches the existing
|
34
|
+
# record’s id, then the existing record will be modified. Otherwise a new
|
35
|
+
# record will be built.
|
36
|
+
#
|
37
|
+
# If the given attributes include a matching <tt>:id</tt> attribute _and_ a
|
38
|
+
# <tt>:_delete</tt> key set to a truthy value, then the existing record
|
39
|
+
# will be marked for destruction.
|
40
|
+
#
|
41
|
+
# @param relationship [DataMapper::Associations::Relationship]
|
42
|
+
# The relationship backing the association.
|
43
|
+
# Assignment will happen on the target end of the relationship
|
44
|
+
#
|
45
|
+
# @param attributes [Hash]
|
46
|
+
# The attributes to assign to the relationship's target end
|
47
|
+
# All attributes except @see UNASSIGNABLE_KEYS will be assigned
|
48
|
+
#
|
49
|
+
# @return nil
|
50
|
+
def assign_nested_attributes_for_related_resource(relationship, attributes)
|
51
|
+
if attributes[:id].blank?
|
52
|
+
return if reject_new_record?(relationship, attributes)
|
53
|
+
new_record = relationship.target_model.new(attributes.except(*UNASSIGNABLE_KEYS))
|
54
|
+
relationship.set(self, new_record)
|
55
|
+
else
|
56
|
+
existing_record = relationship.get(self)
|
57
|
+
if existing_record && existing_record.id.to_s == attributes[:id].to_s
|
58
|
+
assign_to_or_mark_for_destruction(relationship, existing_record, attributes)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Assigns the given attributes to the collection association.
|
65
|
+
#
|
66
|
+
# Hashes with an <tt>:id</tt> value matching an existing associated record
|
67
|
+
# will update that record. Hashes without an <tt>:id</tt> value will build
|
68
|
+
# a new record for the association. Hashes with a matching <tt>:id</tt>
|
69
|
+
# value and a <tt>:_delete</tt> key set to a truthy value will mark the
|
70
|
+
# matched record for destruction.
|
71
|
+
#
|
72
|
+
# For example:
|
73
|
+
#
|
74
|
+
# assign_nested_attributes_for_collection_association(:people, {
|
75
|
+
# '1' => { :id => '1', :name => 'Peter' },
|
76
|
+
# '2' => { :name => 'John' },
|
77
|
+
# '3' => { :id => '2', :_delete => true }
|
78
|
+
# })
|
79
|
+
#
|
80
|
+
# Will update the name of the Person with ID 1, build a new associated
|
81
|
+
# person with the name `John', and mark the associatied Person with ID 2
|
82
|
+
# for destruction.
|
83
|
+
#
|
84
|
+
# Also accepts an Array of attribute hashes:
|
85
|
+
#
|
86
|
+
# assign_nested_attributes_for_collection_association(:people, [
|
87
|
+
# { :id => '1', :name => 'Peter' },
|
88
|
+
# { :name => 'John' },
|
89
|
+
# { :id => '2', :_delete => true }
|
90
|
+
# ])
|
91
|
+
#
|
92
|
+
# @param relationship [DataMapper::Associations::Relationship]
|
93
|
+
# The relationship backing the association.
|
94
|
+
# Assignment will happen on the target end of the relationship
|
95
|
+
#
|
96
|
+
# @param attributes [Hash]
|
97
|
+
# The attributes to assign to the relationship's target end
|
98
|
+
# All attributes except @see UNASSIGNABLE_KEYS will be assigned
|
99
|
+
#
|
100
|
+
# @return nil
|
101
|
+
def assign_nested_attributes_for_related_collection(relationship, attributes_collection)
|
20
102
|
|
21
|
-
|
22
|
-
|
103
|
+
normalize_attributes_collection(attributes_collection).each do |attributes|
|
104
|
+
|
105
|
+
if attributes[:id].blank?
|
106
|
+
next if reject_new_record?(relationship, attributes)
|
107
|
+
relationship.get(self).new(attributes.except(*UNASSIGNABLE_KEYS))
|
108
|
+
else
|
109
|
+
collection = relationship.get(self)
|
110
|
+
if existing_record = collection.detect { |record| record.id.to_s == attributes[:id].to_s }
|
111
|
+
assign_to_or_mark_for_destruction(relationship, existing_record, attributes)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
23
116
|
|
24
|
-
|
25
|
-
|
117
|
+
end
|
26
118
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
119
|
+
##
|
120
|
+
# Updates a record with the +attributes+ or marks it for destruction if
|
121
|
+
# +allow_destroy+ is +true+ and has_delete_flag? returns +true+.
|
122
|
+
#
|
123
|
+
# @param relationship [DataMapper::Associations::Relationship]
|
124
|
+
# The relationship backing the association.
|
125
|
+
# Assignment will happen on the target end of the relationship
|
126
|
+
#
|
127
|
+
# @param attributes [Hash]
|
128
|
+
# The attributes to assign to the relationship's target end
|
129
|
+
# All attributes except @see UNASSIGNABLE_KEYS will be assigned
|
130
|
+
#
|
131
|
+
# @return nil
|
132
|
+
def assign_to_or_mark_for_destruction(relationship, resource, attributes)
|
133
|
+
allow_destroy = self.class.options_for_nested_attributes[relationship][:allow_destroy]
|
134
|
+
if has_delete_flag?(attributes) && allow_destroy
|
135
|
+
resource.mark_for_destruction
|
136
|
+
else
|
137
|
+
resource.update(attributes.except(*UNASSIGNABLE_KEYS))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Determines if a hash contains a truthy _delete key.
|
143
|
+
#
|
144
|
+
# @param hash [Hash] The hash to test
|
145
|
+
#
|
146
|
+
# @return [Boolean]
|
147
|
+
# true, if hash containts a truthy _delete key
|
148
|
+
# false, otherwise
|
149
|
+
def has_delete_flag?(hash)
|
150
|
+
# TODO find out if this activerecord code needs to be ported
|
151
|
+
# ConnectionAdapters::Column.value_to_boolean hash['_delete']
|
152
|
+
hash[:_delete]
|
153
|
+
end
|
31
154
|
|
32
|
-
|
33
|
-
|
155
|
+
##
|
156
|
+
# Determines if a new record should be build by checking for
|
157
|
+
# has_delete_flag? or if a <tt>:reject_if</tt> proc exists for this
|
158
|
+
# association and evaluates to +true+.
|
159
|
+
#
|
160
|
+
# @param relationship [DataMapper::Associations::Relationship]
|
161
|
+
# The relationship backing the association.
|
162
|
+
# Assignment will happen on the target end of the relationship
|
163
|
+
#
|
164
|
+
# @param attributes [Hash]
|
165
|
+
# The attributes to assign to the relationship's target end
|
166
|
+
# All attributes except @see UNASSIGNABLE_KEYS will be assigned
|
167
|
+
#
|
168
|
+
# @return [Boolean]
|
169
|
+
# true, if the given attributes won't be rejected
|
170
|
+
# false, otherwise
|
171
|
+
def reject_new_record?(relationship, attributes)
|
172
|
+
guard = self.class.options_for_nested_attributes[relationship][:reject_if]
|
173
|
+
return false if guard.nil? # if relationship guard is nil, nothing will be rejected
|
174
|
+
has_delete_flag?(attributes) || evaluate_reject_new_record_guard(guard, attributes)
|
175
|
+
end
|
176
|
+
|
177
|
+
def evaluate_reject_new_record_guard(guard, attributes)
|
178
|
+
if guard.is_a?(Symbol) || guard.is_a?(String)
|
179
|
+
send(guard)
|
180
|
+
elsif guard.respond_to?(:call)
|
181
|
+
guard.call(attributes)
|
182
|
+
else
|
183
|
+
# never reached when called from inside the plugin
|
184
|
+
raise ArgumentError, "guard must be a Symbol, a String, or respond_to?(:call)"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def normalize_attributes_collection(attributes_collection)
|
189
|
+
if attributes_collection.is_a?(Hash)
|
190
|
+
attributes_collection.sort_by { |index, _| index.to_i }.map { |_, attributes| attributes }
|
191
|
+
else
|
192
|
+
attributes_collection
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
34
196
|
end
|
35
197
|
|
36
|
-
|
37
|
-
|
38
|
-
|
198
|
+
module CommonResourceSupport
|
199
|
+
|
200
|
+
##
|
201
|
+
# remove mark for destruction if present
|
202
|
+
# before delegating reload behavior to super
|
203
|
+
#
|
204
|
+
# @return The same value that super returns
|
205
|
+
def reload
|
206
|
+
@marked_for_destruction = false
|
207
|
+
super
|
208
|
+
end
|
209
|
+
|
210
|
+
##
|
211
|
+
# Test if this resource is marked for destruction
|
212
|
+
#
|
213
|
+
# @return [Boolean]
|
214
|
+
# true, if this resource is marked for destruction
|
215
|
+
# false, otherwise
|
216
|
+
def marked_for_destruction?
|
217
|
+
@marked_for_destruction
|
218
|
+
end
|
219
|
+
|
220
|
+
##
|
221
|
+
# Mark this resource for destruction
|
222
|
+
#
|
223
|
+
# @return true
|
224
|
+
def mark_for_destruction
|
225
|
+
@marked_for_destruction = true
|
226
|
+
end
|
227
|
+
|
39
228
|
end
|
40
|
-
|
229
|
+
|
41
230
|
end
|
42
|
-
end
|
231
|
+
end
|