active-fedora 9.10.0.pre2 → 9.10.0
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/.rubocop.yml +1 -0
- data/History.txt +141 -0
- data/lib/active_fedora/associations/association.rb +38 -12
- data/lib/active_fedora/associations/association_scope.rb +6 -2
- data/lib/active_fedora/associations/basic_contains_association.rb +2 -3
- data/lib/active_fedora/associations/belongs_to_association.rb +23 -4
- data/lib/active_fedora/associations/builder/association.rb +37 -56
- data/lib/active_fedora/associations/builder/belongs_to.rb +27 -1
- data/lib/active_fedora/associations/builder/collection_association.rb +33 -2
- data/lib/active_fedora/associations/builder/contains.rb +3 -3
- data/lib/active_fedora/associations/builder/directly_contains.rb +1 -7
- data/lib/active_fedora/associations/builder/directly_contains_one.rb +20 -17
- data/lib/active_fedora/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_fedora/associations/builder/has_many.rb +2 -43
- data/lib/active_fedora/associations/builder/indirectly_contains.rb +1 -7
- data/lib/active_fedora/associations/builder/property.rb +2 -13
- data/lib/active_fedora/associations/builder/singular_association.rb +2 -6
- data/lib/active_fedora/associations/builder/singular_property.rb +2 -3
- data/lib/active_fedora/associations/collection_association.rb +6 -14
- data/lib/active_fedora/associations/directly_contains_one_association.rb +1 -2
- data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +1 -1
- data/lib/active_fedora/associations/has_many_association.rb +23 -0
- data/lib/active_fedora/attached_files.rb +1 -1
- data/lib/active_fedora/core.rb +2 -1
- data/lib/active_fedora/errors.rb +13 -0
- data/lib/active_fedora/file.rb +16 -1
- data/lib/active_fedora/file/attributes.rb +6 -6
- data/lib/active_fedora/reflection.rb +200 -76
- data/lib/active_fedora/version.rb +1 -1
- data/lib/active_fedora/with_metadata/metadata_node.rb +2 -1
- data/lib/generators/active_fedora/config/fedora/fedora_generator.rb +4 -0
- data/lib/generators/active_fedora/config/fedora/templates/.fcrepo_wrapper +3 -0
- data/lib/generators/active_fedora/config/solr/solr_generator.rb +4 -0
- data/lib/generators/active_fedora/config/solr/templates/.solr_wrapper +5 -0
- data/spec/integration/attached_files_spec.rb +4 -4
- data/spec/integration/file_spec.rb +1 -1
- data/spec/integration/om_datastream_spec.rb +6 -6
- data/spec/unit/collection_proxy_spec.rb +1 -1
- data/spec/unit/file_spec.rb +19 -0
- data/spec/unit/has_and_belongs_to_many_association_spec.rb +4 -4
- data/spec/unit/has_many_association_spec.rb +2 -2
- data/spec/unit/reflection_spec.rb +2 -2
- metadata +6 -4
@@ -4,10 +4,36 @@ module ActiveFedora::Associations::Builder
|
|
4
4
|
:belongs_to
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
7
|
+
def self.valid_options(options)
|
8
|
+
super + [:optional]
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.valid_dependent_options
|
12
|
+
[:destroy, :delete]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.validate_options(options)
|
8
16
|
super
|
9
17
|
raise "You must specify a predicate for #{name}" unless options[:predicate]
|
10
18
|
raise ArgumentError, "Predicate must be a kind of RDF::URI" unless options[:predicate].is_a?(RDF::URI)
|
11
19
|
end
|
20
|
+
|
21
|
+
def self.define_validations(model, reflection)
|
22
|
+
if reflection.options.key?(:required)
|
23
|
+
reflection.options[:optional] = !reflection.options.delete(:required)
|
24
|
+
end
|
25
|
+
|
26
|
+
required = if reflection.options[:optional].nil?
|
27
|
+
model.belongs_to_required_by_default
|
28
|
+
else
|
29
|
+
!reflection.options[:optional]
|
30
|
+
end
|
31
|
+
|
32
|
+
super
|
33
|
+
|
34
|
+
if required
|
35
|
+
model.validates_presence_of reflection.name, message: :required
|
36
|
+
end
|
37
|
+
end
|
12
38
|
end
|
13
39
|
end
|
@@ -8,18 +8,49 @@ module ActiveFedora::Associations::Builder
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.define_callbacks(model, reflection)
|
11
|
+
super
|
11
12
|
name = reflection.name
|
12
13
|
options = reflection.options
|
13
|
-
super
|
14
14
|
CALLBACKS.each { |callback_name| define_callback(model, callback_name, name, options) }
|
15
15
|
end
|
16
16
|
|
17
|
+
def self.define_extensions(model, name)
|
18
|
+
if block_given?
|
19
|
+
extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
|
20
|
+
extension = Module.new(&Proc.new)
|
21
|
+
model.parent.const_set(extension_module_name, extension)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
17
25
|
def self.define_callback(model, callback_name, name, options)
|
18
26
|
full_callback_name = "#{callback_name}_for_#{name}"
|
19
27
|
|
20
28
|
# TODO : why do i need method_defined? I think its because of the inheritance chain
|
21
29
|
model.class_attribute full_callback_name.to_sym unless model.method_defined?(full_callback_name)
|
22
|
-
|
30
|
+
|
31
|
+
callbacks = Array(options[callback_name.to_sym]).map do |callback|
|
32
|
+
case callback
|
33
|
+
when Symbol
|
34
|
+
->(_method, owner, record) { owner.send(callback, record) }
|
35
|
+
when Proc
|
36
|
+
->(_method, owner, record) { callback.call(owner, record) }
|
37
|
+
else
|
38
|
+
->(method, owner, record) { callback.send(method, owner, record) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
model.send("#{full_callback_name}=", callbacks)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.wrap_scope(scope, mod)
|
45
|
+
if scope
|
46
|
+
if scope.arity > 0
|
47
|
+
proc { |owner| instance_exec(owner, &scope).extending(mod) }
|
48
|
+
else
|
49
|
+
proc { instance_exec(&scope).extending(mod) }
|
50
|
+
end
|
51
|
+
else
|
52
|
+
proc { extending(mod) }
|
53
|
+
end
|
23
54
|
end
|
24
55
|
end
|
25
56
|
end
|
@@ -8,12 +8,12 @@ module ActiveFedora::Associations::Builder
|
|
8
8
|
super + [:autocreate, :block]
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
super
|
11
|
+
def self.create_reflection(model, name, scope, options, extension = nil)
|
13
12
|
options[:class_name] = 'ActiveFedora::File' if options[:class_name].blank?
|
13
|
+
super(model, name, scope, options, extension)
|
14
14
|
end
|
15
15
|
|
16
|
-
def validate_options
|
16
|
+
def self.validate_options(options)
|
17
17
|
super
|
18
18
|
return unless options[:class_name] && !options[:class_name].is_a?(String)
|
19
19
|
raise ArgumentError, ":class_name must be a string for contains '#{name}'"
|
@@ -8,13 +8,7 @@ module ActiveFedora::Associations::Builder
|
|
8
8
|
super + [:has_member_relation, :is_member_of_relation] - [:predicate]
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
reflection = super
|
13
|
-
configure_dependency
|
14
|
-
reflection
|
15
|
-
end
|
16
|
-
|
17
|
-
def validate_options
|
11
|
+
def self.validate_options(options)
|
18
12
|
super
|
19
13
|
if !options[:has_member_relation] && !options[:is_member_of_relation]
|
20
14
|
raise ArgumentError, "You must specify a :has_member_relation or :is_member_of_relation predicate for #{name}"
|
@@ -8,11 +8,18 @@ module ActiveFedora::Associations::Builder
|
|
8
8
|
super + [:has_member_relation, :is_member_of_relation, :type, :through] - [:predicate]
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
11
|
+
def self.create_reflection(model, name, scope, options, extension = nil)
|
12
|
+
if options[:through]
|
13
|
+
inherit_options_from_association(model, options, options[:through])
|
14
|
+
else
|
15
|
+
raise ArgumentError, "you must specify a :through option on #{name}. #{name} will use the container from that directly_contains association."
|
16
|
+
end
|
17
|
+
|
14
18
|
super
|
19
|
+
end
|
15
20
|
|
21
|
+
def self.validate_options(options)
|
22
|
+
super
|
16
23
|
if options[:class_name] == "ActiveFedora::File"
|
17
24
|
raise ArgumentError, "You cannot set :class_name of #{name} to ActiveFedora::File because directly_contains_one needs to assert and read RDF.type assertions, which is not supported by ActiveFedora::File. To make Files support RDF.type assertions, define a subclass of ActiveFedora::File and make it `include ActiveFedora::WithMetadata`. Otherwise, all subclasses of ActiveFedora::Base support RDF.type assertions."
|
18
25
|
elsif !options[:has_member_relation] && !options[:is_member_of_relation]
|
@@ -25,20 +32,16 @@ module ActiveFedora::Associations::Builder
|
|
25
32
|
raise ArgumentError, "You must specify a Type and it must be a kind of RDF::URI"
|
26
33
|
end
|
27
34
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
options[:class_name] = associated_through_reflection.options[:class_name] unless options[:class_name] && options[:class_name] != "ActiveFedora::File"
|
38
|
-
end
|
35
|
+
# Inherits :has_member_relation from the association corresponding to association_name
|
36
|
+
# @param [Symbol] association_name of the association to inherit from
|
37
|
+
def self.inherit_options_from_association(model, options, association_name)
|
38
|
+
associated_through_reflection = model._reflect_on_association(association_name)
|
39
|
+
raise ArgumentError, "You specified `:through => #{@reflection.options[:through]}` on the #{name} associaiton but #{model} does not actually have a #{@reflection.options[:through]}` association" if associated_through_reflection.nil? || !associated_through_reflection.name
|
40
|
+
raise ArgumentError, "You must specify a directly_contains association as the :through option on #{name}. You provided a #{associated_through_reflection.macro}" unless associated_through_reflection.macro == :directly_contains
|
41
|
+
options[:has_member_relation] = associated_through_reflection.options[:has_member_relation] unless options[:has_member_relation]
|
42
|
+
options[:class_name] = associated_through_reflection.options[:class_name] unless options[:class_name] && options[:class_name] != "ActiveFedora::File"
|
43
|
+
end
|
39
44
|
|
40
|
-
|
41
|
-
model._reflect_on_association(association_name)
|
42
|
-
end
|
45
|
+
private_class_method :inherit_options_from_association
|
43
46
|
end
|
44
47
|
end
|
@@ -9,7 +9,7 @@ module ActiveFedora::Associations::Builder
|
|
9
9
|
super + [:inverse_of, :solr_page_size]
|
10
10
|
end
|
11
11
|
|
12
|
-
def validate_options
|
12
|
+
def self.validate_options(options)
|
13
13
|
super
|
14
14
|
Deprecation.warn HasAndBelongsToMany, ":solr_page_size doesn't do anything anymore and will be removed in ActiveFedora 10" if options.key?(:solr_page_size)
|
15
15
|
raise "You must specify a predicate for #{name}" unless options[:predicate]
|
@@ -8,10 +8,8 @@ module ActiveFedora::Associations::Builder
|
|
8
8
|
super + [:as, :dependent, :inverse_of]
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
configure_dependency
|
14
|
-
reflection
|
11
|
+
def self.valid_dependent_options
|
12
|
+
[:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception]
|
15
13
|
end
|
16
14
|
|
17
15
|
def self.define_readers(mixin, name)
|
@@ -29,44 +27,5 @@ module ActiveFedora::Associations::Builder
|
|
29
27
|
association(name).ids_writer(ids)
|
30
28
|
end
|
31
29
|
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def configure_dependency
|
36
|
-
return unless options[:dependent]
|
37
|
-
unless [:destroy, :delete_all, :nullify, :restrict].include?(options[:dependent])
|
38
|
-
raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, " \
|
39
|
-
":nullify or :restrict (#{options[:dependent].inspect})"
|
40
|
-
end
|
41
|
-
|
42
|
-
send("define_#{options[:dependent]}_dependency_method")
|
43
|
-
model.before_destroy dependency_method_name
|
44
|
-
end
|
45
|
-
|
46
|
-
def define_destroy_dependency_method
|
47
|
-
name = self.name
|
48
|
-
model.send(:define_method, dependency_method_name) do
|
49
|
-
send(name).delete_all
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def define_delete_all_dependency_method
|
54
|
-
name = self.name
|
55
|
-
model.send(:define_method, dependency_method_name) do
|
56
|
-
send(name).delete_all
|
57
|
-
end
|
58
|
-
end
|
59
|
-
alias define_nullify_dependency_method define_delete_all_dependency_method
|
60
|
-
|
61
|
-
def define_restrict_dependency_method
|
62
|
-
name = self.name
|
63
|
-
model.send(:define_method, dependency_method_name) do
|
64
|
-
raise ActiveRecord::DeleteRestrictionError, name unless send(name).empty?
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def dependency_method_name
|
69
|
-
"has_many_dependent_for_#{name}"
|
70
|
-
end
|
71
30
|
end
|
72
31
|
end
|
@@ -8,12 +8,6 @@ module ActiveFedora::Associations::Builder
|
|
8
8
|
super + [:has_member_relation, :is_member_of_relation, :inserted_content_relation, :foreign_key, :through] - [:predicate]
|
9
9
|
end
|
10
10
|
|
11
|
-
def build
|
12
|
-
reflection = super
|
13
|
-
configure_dependency
|
14
|
-
reflection
|
15
|
-
end
|
16
|
-
|
17
11
|
def self.define_readers(mixin, name)
|
18
12
|
super
|
19
13
|
|
@@ -22,7 +16,7 @@ module ActiveFedora::Associations::Builder
|
|
22
16
|
end
|
23
17
|
end
|
24
18
|
|
25
|
-
def validate_options
|
19
|
+
def self.validate_options(options)
|
26
20
|
super
|
27
21
|
if !options[:has_member_relation] && !options[:is_member_of_relation]
|
28
22
|
raise ArgumentError, "You must specify a predicate for #{name}"
|
@@ -8,19 +8,8 @@ module ActiveFedora::Associations::Builder
|
|
8
8
|
super
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
@name = :"#{name.to_s.singularize}_ids"
|
14
|
-
end
|
15
|
-
|
16
|
-
def build
|
17
|
-
super.tap do |reflection|
|
18
|
-
model.index_config[name] = build_index_config(reflection)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def build_index_config(reflection)
|
23
|
-
ActiveFedora::Indexing::Map::IndexObject.new(reflection.predicate_for_solr) { |index| index.as :symbol }
|
11
|
+
def self.better_name(name)
|
12
|
+
:"#{name.to_s.singularize}_ids"
|
24
13
|
end
|
25
14
|
end
|
26
15
|
end
|
@@ -1,16 +1,12 @@
|
|
1
1
|
module ActiveFedora::Associations::Builder
|
2
2
|
class SingularAssociation < Association #:nodoc:
|
3
3
|
def self.valid_options(options)
|
4
|
-
super + [:dependent, :inverse_of]
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.constructable?
|
8
|
-
true
|
4
|
+
super + [:dependent, :inverse_of, :required]
|
9
5
|
end
|
10
6
|
|
11
7
|
def self.define_accessors(model, reflection)
|
12
8
|
super
|
13
|
-
define_constructors(model.generated_association_methods, reflection.name) if constructable?
|
9
|
+
define_constructors(model.generated_association_methods, reflection.name) if reflection.constructable?
|
14
10
|
end
|
15
11
|
|
16
12
|
def self.define_constructors(mixin, name)
|
@@ -100,7 +100,7 @@ module ActiveFedora
|
|
100
100
|
# Replace this collection with +other_array+
|
101
101
|
# This will perform a diff and delete/add only records that have changed.
|
102
102
|
def replace(other_array)
|
103
|
-
other_array.each { |val| raise_on_type_mismatch(val) }
|
103
|
+
other_array.each { |val| raise_on_type_mismatch!(val) }
|
104
104
|
|
105
105
|
load_target
|
106
106
|
other = other_array.size < 100 ? other_array : other_array.to_set
|
@@ -156,8 +156,7 @@ module ActiveFedora
|
|
156
156
|
result = true
|
157
157
|
|
158
158
|
records.flatten.each do |record|
|
159
|
-
raise_on_type_mismatch(record)
|
160
|
-
run_type_validator(record)
|
159
|
+
raise_on_type_mismatch!(record)
|
161
160
|
add_to_target(record) do |_r|
|
162
161
|
result &&= insert_record(record) unless owner.new_record?
|
163
162
|
end
|
@@ -356,7 +355,7 @@ module ActiveFedora
|
|
356
355
|
|
357
356
|
def delete_or_destroy(records, method)
|
358
357
|
records = records.flatten.select { |x| load_target.include?(x) }
|
359
|
-
records.each { |record| raise_on_type_mismatch(record) }
|
358
|
+
records.each { |record| raise_on_type_mismatch!(record) }
|
360
359
|
existing_records = records.select(&:persisted?)
|
361
360
|
|
362
361
|
records.each { |record| callback(:before_remove, record) }
|
@@ -374,20 +373,13 @@ module ActiveFedora
|
|
374
373
|
|
375
374
|
def callback(method, record)
|
376
375
|
callbacks_for(method).each do |callback|
|
377
|
-
|
378
|
-
when Symbol
|
379
|
-
@owner.send(callback, record)
|
380
|
-
when Proc
|
381
|
-
callback.call(@owner, record)
|
382
|
-
else
|
383
|
-
callback.send(method, @owner, record)
|
384
|
-
end
|
376
|
+
callback.call(method, owner, record)
|
385
377
|
end
|
386
378
|
end
|
387
379
|
|
388
380
|
def callbacks_for(callback_name)
|
389
|
-
full_callback_name = "#{callback_name}_for_#{
|
390
|
-
|
381
|
+
full_callback_name = "#{callback_name}_for_#{reflection.name}"
|
382
|
+
owner.class.send(full_callback_name)
|
391
383
|
end
|
392
384
|
|
393
385
|
def ensure_owner_is_not_new
|
@@ -33,8 +33,7 @@ module ActiveFedora
|
|
33
33
|
# Ensures that this association's +type+ is set on the record and adds the record to the association's DirectContainer
|
34
34
|
def replace(record, *)
|
35
35
|
if record
|
36
|
-
raise_on_type_mismatch(record)
|
37
|
-
run_type_validator(record)
|
36
|
+
raise_on_type_mismatch!(record)
|
38
37
|
remove_existing_target
|
39
38
|
add_type_to_record(record, options[:type])
|
40
39
|
add_to_container(record)
|
@@ -57,6 +57,29 @@ module ActiveFedora
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
def handle_dependency
|
61
|
+
case options[:dependent]
|
62
|
+
when :restrict_with_exception
|
63
|
+
raise ActiveFedora::DeleteRestrictionError, reflection.name unless empty?
|
64
|
+
|
65
|
+
when :restrict_with_error
|
66
|
+
unless empty?
|
67
|
+
record = owner.class.human_attribute_name(reflection.name).downcase
|
68
|
+
owner.errors.add(:base, message || :'restrict_dependent_destroy.has_many', record: record)
|
69
|
+
throw(:abort)
|
70
|
+
end
|
71
|
+
|
72
|
+
else
|
73
|
+
if options[:dependent] == :destroy
|
74
|
+
# No point in executing the counter update since we're going to destroy the parent anyway
|
75
|
+
load_target.each { |t| t.destroyed_by_association = reflection }
|
76
|
+
destroy_all
|
77
|
+
else
|
78
|
+
delete_all
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
60
83
|
protected
|
61
84
|
|
62
85
|
def find_polymorphic_inverse(record)
|
@@ -131,7 +131,7 @@ module ActiveFedora
|
|
131
131
|
|
132
132
|
def create_singleton_association(file_path)
|
133
133
|
undeclared_files << file_path.to_sym
|
134
|
-
association = Associations::BasicContainsAssociation.new(self, Reflection::AssociationReflection.new(:contains, file_path, { class_name: 'ActiveFedora::File' }, self.class))
|
134
|
+
association = Associations::BasicContainsAssociation.new(self, Reflection::AssociationReflection.new(:contains, file_path, nil, { class_name: 'ActiveFedora::File' }, self.class))
|
135
135
|
@association_cache[file_path.to_sym] = association
|
136
136
|
|
137
137
|
singleton_class.send :define_method, accessor_name(file_path) do
|
data/lib/active_fedora/core.rb
CHANGED
@@ -14,6 +14,7 @@ module ActiveFedora
|
|
14
14
|
# Accepts a logger conforming to the interface of Log4r which can be
|
15
15
|
# retrieved on both a class and instance level by calling +logger+.
|
16
16
|
mattr_accessor :logger, instance_writer: false
|
17
|
+
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
|
17
18
|
end
|
18
19
|
|
19
20
|
# Constructor. You may supply a custom +:id+, or we call the Fedora Rest API for the
|
@@ -31,7 +32,7 @@ module ActiveFedora
|
|
31
32
|
assign_attributes(attributes) if attributes
|
32
33
|
|
33
34
|
yield self if block_given?
|
34
|
-
|
35
|
+
_run_initialize_callbacks
|
35
36
|
end
|
36
37
|
|
37
38
|
##
|