active-fedora 9.9.1 → 9.10.0.pre1
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 +4 -2
- data/.travis.yml +2 -6
- data/active-fedora.gemspec +9 -6
- data/lib/active_fedora.rb +31 -15
- data/lib/active_fedora/associations.rb +1 -1
- data/lib/active_fedora/associations/association.rb +6 -2
- data/lib/active_fedora/associations/belongs_to_association.rb +0 -10
- data/lib/active_fedora/associations/builder/association.rb +85 -12
- data/lib/active_fedora/associations/builder/belongs_to.rb +3 -1
- data/lib/active_fedora/associations/builder/collection_association.rb +4 -3
- data/lib/active_fedora/associations/builder/contains.rb +7 -2
- data/lib/active_fedora/associations/builder/directly_contains.rb +7 -3
- data/lib/active_fedora/associations/builder/directly_contains_one.rb +8 -4
- data/lib/active_fedora/associations/builder/has_and_belongs_to_many.rb +6 -2
- data/lib/active_fedora/associations/builder/has_many.rb +6 -2
- data/lib/active_fedora/associations/builder/indirectly_contains.rb +7 -3
- data/lib/active_fedora/associations/builder/property.rb +7 -2
- data/lib/active_fedora/associations/builder/singular_association.rb +3 -1
- data/lib/active_fedora/associations/builder/singular_property.rb +3 -1
- data/lib/active_fedora/associations/collection_association.rb +9 -5
- data/lib/active_fedora/associations/collection_proxy.rb +1 -1
- data/lib/active_fedora/associations/contained_finder.rb +1 -2
- data/lib/active_fedora/associations/directly_contains_one_association.rb +1 -1
- data/lib/active_fedora/associations/has_many_association.rb +1 -5
- data/lib/active_fedora/associations/rdf.rb +1 -20
- data/lib/active_fedora/attached_files.rb +1 -1
- data/lib/active_fedora/attribute_methods.rb +18 -0
- data/lib/active_fedora/attributes.rb +1 -1
- data/lib/active_fedora/autosave_association.rb +8 -12
- data/lib/active_fedora/base.rb +0 -2
- data/lib/active_fedora/caching_connection.rb +1 -1
- data/lib/active_fedora/default_model_mapper.rb +24 -0
- data/lib/active_fedora/fedora.rb +1 -1
- data/lib/active_fedora/file/attributes.rb +4 -5
- data/lib/active_fedora/identifiable.rb +5 -0
- data/lib/active_fedora/indexing.rb +13 -7
- data/lib/active_fedora/indexing_service.rb +4 -4
- data/lib/active_fedora/ldp_resource.rb +1 -0
- data/lib/active_fedora/model.rb +18 -16
- data/lib/active_fedora/model_classifier.rb +77 -0
- data/lib/active_fedora/nested_attributes.rb +145 -18
- data/lib/active_fedora/persistence.rb +1 -1
- data/lib/active_fedora/predicates.rb +3 -0
- data/lib/active_fedora/qualified_dublin_core_datastream.rb +1 -1
- data/lib/active_fedora/query_result_builder.rb +12 -28
- data/lib/active_fedora/querying.rb +1 -1
- data/lib/active_fedora/rdf/datastream_indexing.rb +1 -1
- data/lib/active_fedora/reflection.rb +15 -7
- data/lib/active_fedora/relation.rb +17 -0
- data/lib/active_fedora/relation/calculations.rb +1 -5
- data/lib/active_fedora/relation/finder_methods.rb +39 -26
- data/lib/active_fedora/scoping.rb +5 -0
- data/lib/active_fedora/scoping/default.rb +113 -0
- data/lib/active_fedora/scoping/named.rb +11 -3
- data/lib/active_fedora/simple_datastream.rb +1 -1
- data/lib/active_fedora/solr_hit.rb +71 -0
- data/lib/active_fedora/solr_instance_loader.rb +12 -36
- data/lib/active_fedora/solr_query_builder.rb +20 -25
- data/lib/active_fedora/solr_service.rb +24 -13
- data/lib/active_fedora/type.rb +8 -0
- data/lib/active_fedora/type/boolean.rb +23 -0
- data/lib/active_fedora/type/value.rb +118 -0
- data/lib/active_fedora/validations.rb +14 -5
- data/lib/active_fedora/version.rb +1 -1
- data/lib/active_fedora/versionable.rb +8 -7
- data/spec/config_helper.rb +0 -5
- data/spec/integration/associations_spec.rb +5 -5
- data/spec/integration/base_spec.rb +4 -4
- data/spec/integration/bug_spec.rb +0 -1
- data/spec/integration/full_featured_model_spec.rb +4 -4
- data/spec/integration/has_and_belongs_to_many_associations_spec.rb +1 -1
- data/spec/integration/has_many_associations_spec.rb +30 -1
- data/spec/integration/indirect_container_spec.rb +1 -1
- data/spec/integration/nested_attribute_spec.rb +6 -0
- data/spec/integration/ntriples_datastream_spec.rb +4 -4
- data/spec/integration/om_datastream_spec.rb +1 -1
- data/spec/integration/relation_delegation_spec.rb +1 -1
- data/spec/integration/scoped_query_spec.rb +12 -12
- data/spec/integration/solr_hit_spec.rb +52 -0
- data/spec/samples/hydra-mods_article_datastream.rb +2 -2
- data/spec/spec_helper.rb +5 -9
- data/spec/unit/active_fedora_spec.rb +0 -26
- data/spec/unit/base_spec.rb +20 -0
- data/spec/unit/builder/has_and_belongs_to_many_spec.rb +2 -3
- data/spec/unit/callback_spec.rb +3 -8
- data/spec/unit/default_model_mapper_spec.rb +39 -0
- data/spec/unit/finder_methods_spec.rb +30 -6
- data/spec/unit/has_many_association_spec.rb +23 -1
- data/spec/unit/indexing_spec.rb +17 -3
- data/spec/unit/model_classifier_spec.rb +49 -0
- data/spec/unit/model_spec.rb +0 -9
- data/spec/unit/ntriples_datastream_spec.rb +16 -16
- data/spec/unit/om_datastream_spec.rb +7 -7
- data/spec/unit/qualified_dublin_core_datastream_spec.rb +1 -1
- data/spec/unit/query_result_builder_spec.rb +4 -10
- data/spec/unit/query_spec.rb +28 -28
- data/spec/unit/rdf/indexing_service_spec.rb +16 -16
- data/spec/unit/scoping_spec.rb +67 -0
- data/spec/unit/simple_datastream_spec.rb +2 -2
- data/spec/unit/solr_config_options_spec.rb +29 -32
- data/spec/unit/solr_hit_spec.rb +58 -0
- data/spec/unit/solr_query_builder_spec.rb +9 -1
- data/spec/unit/solr_service_spec.rb +19 -3
- metadata +73 -17
- data/spec/support/freeze_mocks.rb +0 -12
@@ -1,50 +1,34 @@
|
|
1
1
|
module ActiveFedora
|
2
2
|
module QueryResultBuilder
|
3
3
|
def self.lazy_reify_solr_results(solr_results, opts = {})
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
return to_enum(:lazy_reify_solr_results, solr_results, opts) unless block_given?
|
5
|
+
|
6
|
+
solr_results.each do |hit|
|
7
|
+
yield ActiveFedora::SolrHit.for(hit).reify(opts)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.reify_solr_results(solr_results, opts = {})
|
12
|
-
solr_results
|
12
|
+
lazy_reify_solr_results(solr_results, opts).to_a
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.reify_solr_result(hit, _opts = {})
|
16
|
-
|
17
|
-
|
16
|
+
Deprecation.warn(ActiveFedora::Base, 'ActiveFedora::QueryResultBuilder.reify_solr_result is deprecated and will be removed in ActiveFedora 10.0; call #reify on the SolrHit instead.')
|
17
|
+
ActiveFedora::SolrHit.for(hit).reify
|
18
18
|
end
|
19
19
|
|
20
20
|
# Returns all possible classes for the solr object
|
21
21
|
def self.classes_from_solr_document(hit, _opts = {})
|
22
|
-
|
23
|
-
|
24
|
-
hit[HAS_MODEL_SOLR_FIELD].each { |value| classes << Model.from_class_uri(value) }
|
25
|
-
|
26
|
-
classes.compact
|
22
|
+
Deprecation.warn(ActiveFedora::Base, 'ActiveFedora::QueryResultBuilder.classes_from_solr_document is deprecated and will be removed in ActiveFedora 10.0; call #models on the SolrHit instead.')
|
23
|
+
ActiveFedora::SolrHit.for(hit).models
|
27
24
|
end
|
28
25
|
|
29
26
|
# Returns the best singular class for the solr object
|
30
27
|
def self.class_from_solr_document(hit, opts = {})
|
31
|
-
|
32
|
-
|
33
|
-
Array(hit[HAS_MODEL_SOLR_FIELD]).each do |value|
|
34
|
-
model_value = Model.from_class_uri(value)
|
35
|
-
next unless model_value
|
36
|
-
|
37
|
-
# Set as the first model in case opts[:class] was nil
|
38
|
-
best_model_match ||= model_value
|
39
|
-
|
40
|
-
# If there is an inheritance structure, use the most specific case.
|
41
|
-
best_model_match = model_value if best_model_match > model_value
|
42
|
-
end
|
43
|
-
|
44
|
-
ActiveFedora::Base.logger.warn "Could not find a model for #{hit['id']}, defaulting to ActiveFedora::Base" if ActiveFedora::Base.logger && !best_model_match
|
45
|
-
best_model_match || ActiveFedora::Base
|
28
|
+
Deprecation.warn(ActiveFedora::Base, 'ActiveFedora::QueryResultBuilder.class_from_solr_document is deprecated and will be removed in ActiveFedora 10.0; call #model on the SolrHit instead.')
|
29
|
+
ActiveFedora::SolrHit.for(hit).model(opts)
|
46
30
|
end
|
47
31
|
|
48
|
-
HAS_MODEL_SOLR_FIELD =
|
32
|
+
HAS_MODEL_SOLR_FIELD = ActiveFedora.index_field_mapper.solr_name("has_model", :symbol).freeze
|
49
33
|
end
|
50
34
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveFedora
|
2
2
|
module Querying
|
3
3
|
delegate :find, :first, :exists?, :where, :limit, :offset, :order, :delete_all,
|
4
|
-
:destroy_all, :count, :last, :find_with_conditions, :find_in_batches, :find_each, to: :all
|
4
|
+
:destroy_all, :count, :last, :find_with_conditions, :find_in_batches, :search_with_conditions, :search_in_batches, :search_by_id, :find_each, to: :all
|
5
5
|
|
6
6
|
def self.extended(base)
|
7
7
|
base.class_attribute :solr_query_handler
|
@@ -13,7 +13,7 @@ module ActiveFedora::RDF
|
|
13
13
|
config = self.class.config_for_term_or_uri(field)
|
14
14
|
return nil unless config && config.behaviors # punt on index names for deep nodes!
|
15
15
|
config.behaviors.each do |behavior|
|
16
|
-
result = ActiveFedora
|
16
|
+
result = ActiveFedora.index_field_mapper.solr_name(apply_prefix(field, file_path), behavior, type: config.type)
|
17
17
|
return result if Solrizer::DefaultDescriptors.send(behavior).evaluate_suffix(:text).stored?
|
18
18
|
end
|
19
19
|
raise RuntimeError "no stored fields were found"
|
@@ -50,10 +50,10 @@ module ActiveFedora
|
|
50
50
|
|
51
51
|
# Returns the AssociationReflection object for the +association+ (use the symbol).
|
52
52
|
#
|
53
|
-
# Account.
|
54
|
-
# Invoice.
|
53
|
+
# Account._reflect_on_association(:owner) # returns the owner AssociationReflection
|
54
|
+
# Invoice._reflect_on_association(:line_items).macro # returns :has_many
|
55
55
|
#
|
56
|
-
def
|
56
|
+
def _reflect_on_association(association)
|
57
57
|
val = reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil
|
58
58
|
unless val
|
59
59
|
# When a has_many is paired with a has_and_belongs_to_many the assocation will have a plural name
|
@@ -92,7 +92,7 @@ module ActiveFedora
|
|
92
92
|
# has_many :books
|
93
93
|
# end
|
94
94
|
#
|
95
|
-
# Author.
|
95
|
+
# Author._reflect_on_association(:books).klass
|
96
96
|
# # => Book
|
97
97
|
#
|
98
98
|
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
|
@@ -110,6 +110,12 @@ module ActiveFedora
|
|
110
110
|
@automatic_inverse_of = nil
|
111
111
|
end
|
112
112
|
|
113
|
+
def autosave=(autosave)
|
114
|
+
@options[:autosave] = autosave
|
115
|
+
parent_reflection = self.parent_reflection
|
116
|
+
parent_reflection.autosave = autosave if parent_reflection
|
117
|
+
end
|
118
|
+
|
113
119
|
# Returns a new, unsaved instance of the associated class. +options+ will
|
114
120
|
# be passed to the class's constructor.
|
115
121
|
def build_association(*options, &block)
|
@@ -171,6 +177,8 @@ module ActiveFedora
|
|
171
177
|
# Holds all the meta-data about an association as it was specified in the
|
172
178
|
# Active Record class.
|
173
179
|
class AssociationReflection < MacroReflection #:nodoc:
|
180
|
+
attr_accessor :parent_reflection # Reflection
|
181
|
+
|
174
182
|
def initialize(macro, name, options, active_fedora)
|
175
183
|
super
|
176
184
|
@collection = [:has_many, :has_and_belongs_to_many, :directly_contains, :indirectly_contains].include?(macro)
|
@@ -198,7 +206,7 @@ module ActiveFedora
|
|
198
206
|
|
199
207
|
def solr_key
|
200
208
|
@solr_key ||= begin
|
201
|
-
ActiveFedora
|
209
|
+
ActiveFedora.index_field_mapper.solr_name(predicate_for_solr, :symbol)
|
202
210
|
end
|
203
211
|
end
|
204
212
|
|
@@ -226,7 +234,7 @@ module ActiveFedora
|
|
226
234
|
def inverse_of
|
227
235
|
return unless inverse_name
|
228
236
|
|
229
|
-
@inverse_of ||= klass.
|
237
|
+
@inverse_of ||= klass._reflect_on_association inverse_name
|
230
238
|
end
|
231
239
|
|
232
240
|
# Returns whether or not the association should be validated as part of
|
@@ -299,7 +307,7 @@ module ActiveFedora
|
|
299
307
|
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_fedora.name.demodulize).to_sym
|
300
308
|
|
301
309
|
begin
|
302
|
-
reflection = klass.
|
310
|
+
reflection = klass._reflect_on_association(inverse_name)
|
303
311
|
rescue NameError
|
304
312
|
# Give up: we couldn't compute the klass type so we won't be able
|
305
313
|
# to find any associations either.
|
@@ -62,6 +62,23 @@ module ActiveFedora
|
|
62
62
|
@records
|
63
63
|
end
|
64
64
|
|
65
|
+
# Scope all queries to the current scope.
|
66
|
+
#
|
67
|
+
# Comment.where(post_id: 1).scoping do
|
68
|
+
# Comment.first
|
69
|
+
# end
|
70
|
+
# # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
71
|
+
#
|
72
|
+
# Please check unscoped if you want to remove all previous scopes (including
|
73
|
+
# the default_scope) during the execution of a block.
|
74
|
+
def scoping
|
75
|
+
previous = klass.current_scope
|
76
|
+
klass.current_scope = self
|
77
|
+
yield
|
78
|
+
ensure
|
79
|
+
klass.current_scope = previous
|
80
|
+
end
|
81
|
+
|
65
82
|
def ==(other)
|
66
83
|
case other
|
67
84
|
when Relation
|
@@ -8,11 +8,7 @@ module ActiveFedora
|
|
8
8
|
opts[:rows] = limit_value if limit_value
|
9
9
|
opts[:sort] = order_values if order_values
|
10
10
|
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def calculate(_calculation, conditions, _opts = {})
|
15
|
-
SolrService.query(create_query(conditions), raw: true, rows: 0).fetch('response'.freeze)['numFound'.freeze]
|
11
|
+
SolrService.count(create_query(where_values))
|
16
12
|
end
|
17
13
|
end
|
18
14
|
end
|
@@ -87,7 +87,7 @@ module ActiveFedora
|
|
87
87
|
return false unless conditions
|
88
88
|
case conditions
|
89
89
|
when Hash
|
90
|
-
|
90
|
+
search_with_conditions(conditions, rows: 1).present?
|
91
91
|
when String
|
92
92
|
find(conditions).present?
|
93
93
|
else
|
@@ -102,15 +102,35 @@ module ActiveFedora
|
|
102
102
|
# hash representing the query part of an solr statement. If a hash is
|
103
103
|
# provided, this method will generate conditions based simple equality
|
104
104
|
# combined using the boolean AND operator.
|
105
|
-
# @param[Hash] options
|
105
|
+
# @param [Hash] options
|
106
106
|
# @option opts [Array] :sort a list of fields to sort by
|
107
107
|
# @option opts [Array] :rows number of rows to return
|
108
|
-
def
|
108
|
+
def search_with_conditions(conditions, opts = {})
|
109
109
|
# set default sort to created date ascending
|
110
110
|
opts[:sort] = @klass.default_sort_params unless opts.include?(:sort)
|
111
111
|
SolrService.query(create_query(conditions), opts)
|
112
112
|
end
|
113
113
|
|
114
|
+
# Returns a single solr hit matching the given id
|
115
|
+
# @param [String] id document id
|
116
|
+
# @param [Hash] opts
|
117
|
+
def search_by_id(id, opts = {})
|
118
|
+
opts[:rows] = 1
|
119
|
+
result = search_with_conditions({ id: id }, opts)
|
120
|
+
|
121
|
+
if result.empty?
|
122
|
+
raise ActiveFedora::ObjectNotFoundError, "Object #{id} not found in solr"
|
123
|
+
end
|
124
|
+
|
125
|
+
result.first
|
126
|
+
end
|
127
|
+
|
128
|
+
# @deprecated
|
129
|
+
def find_with_conditions(*args)
|
130
|
+
Deprecation.warn(ActiveFedora::Base, '.find_with_conditions is deprecated and will be removed in active-fedora 10.0; use .search_with_conditions instead')
|
131
|
+
search_with_conditions(*args)
|
132
|
+
end
|
133
|
+
|
114
134
|
# Yields the found ActiveFedora::Base object to the passed block
|
115
135
|
#
|
116
136
|
# @param [Hash] conditions the conditions for the solr search to match
|
@@ -118,12 +138,12 @@ module ActiveFedora
|
|
118
138
|
# @option opts [Boolean] :cast (true) when true, examine the model and cast it to the first known cModel
|
119
139
|
def find_each(conditions = {}, opts = {})
|
120
140
|
cast = opts.delete(:cast)
|
121
|
-
|
141
|
+
search_in_batches(conditions, opts.merge(fl: ActiveFedora.id_field)) do |group|
|
122
142
|
group.each do |hit|
|
123
143
|
begin
|
124
|
-
yield(load_from_fedora(hit[
|
144
|
+
yield(load_from_fedora(hit[ActiveFedora.id_field], cast))
|
125
145
|
rescue Ldp::Gone
|
126
|
-
ActiveFedora::Base.logger.error "Although #{hit[
|
146
|
+
ActiveFedora::Base.logger.error "Although #{hit[ActiveFedora.id_field]} was found in Solr, it doesn't seem to exist in Fedora. The index is out of synch." if ActiveFedora::Base.logger
|
127
147
|
end
|
128
148
|
end
|
129
149
|
end
|
@@ -140,11 +160,10 @@ module ActiveFedora
|
|
140
160
|
# @option opts [Array] :rows number of rows to return
|
141
161
|
#
|
142
162
|
# @example
|
143
|
-
# Person.
|
163
|
+
# Person.search_in_batches('age_t'=>'21', {:batch_size=>50}) do |group|
|
144
164
|
# group.each { |person| puts person['name_t'] }
|
145
165
|
# end
|
146
|
-
|
147
|
-
def find_in_batches(conditions, opts = {})
|
166
|
+
def search_in_batches(conditions, opts = {})
|
148
167
|
opts[:q] = create_query(conditions)
|
149
168
|
opts[:qt] = @klass.solr_query_handler
|
150
169
|
# set default sort to created date ascending
|
@@ -163,6 +182,12 @@ module ActiveFedora
|
|
163
182
|
end
|
164
183
|
end
|
165
184
|
|
185
|
+
# @deprecated
|
186
|
+
def find_in_batches(*args)
|
187
|
+
Deprecation.warn(ActiveFedora::Base, '.find_in_batches is deprecated and will be removed in active-fedora 10.0; use .search_in_batches instead')
|
188
|
+
search_in_batches(*args)
|
189
|
+
end
|
190
|
+
|
166
191
|
# Retrieve the Fedora object with the given id, explore the returned object
|
167
192
|
# Raises a ObjectNotFoundError if the object is not found.
|
168
193
|
# @param [String] id of the object to load
|
@@ -174,7 +199,7 @@ module ActiveFedora
|
|
174
199
|
if where_values.empty?
|
175
200
|
load_from_fedora(id, cast)
|
176
201
|
else
|
177
|
-
conditions = where_values + [ActiveFedora::SolrQueryBuilder.
|
202
|
+
conditions = where_values + [ActiveFedora::SolrQueryBuilder.construct_query(ActiveFedora.id_field => id)]
|
178
203
|
query = conditions.join(" AND ".freeze)
|
179
204
|
to_enum(:find_each, query, {}).to_a.first
|
180
205
|
end
|
@@ -193,8 +218,7 @@ module ActiveFedora
|
|
193
218
|
if @klass == ActiveFedora::Base && cast == false
|
194
219
|
ActiveFedora::Base
|
195
220
|
else
|
196
|
-
|
197
|
-
resource_class = Model.from_class_uri(has_model_value(resource)) || ActiveFedora::Base
|
221
|
+
resource_class = has_model_value(resource)
|
198
222
|
unless equivalent_class?(resource_class)
|
199
223
|
raise ActiveFedora::ActiveFedoraError, "Model mismatch. Expected #{@klass}. Got: #{resource_class}"
|
200
224
|
end
|
@@ -203,18 +227,7 @@ module ActiveFedora
|
|
203
227
|
end
|
204
228
|
|
205
229
|
def has_model_value(resource)
|
206
|
-
|
207
|
-
|
208
|
-
resource.graph.query([nil, ActiveFedora::RDF::Fcrepo::Model.hasModel, nil]).each do |rg|
|
209
|
-
model_value = Model.from_class_uri(rg.object.to_s)
|
210
|
-
next unless model_value
|
211
|
-
best_model_match ||= model_value
|
212
|
-
|
213
|
-
# If there is an inheritance structure, use the most specific case.
|
214
|
-
best_model_match = model_value if best_model_match > model_value
|
215
|
-
end
|
216
|
-
|
217
|
-
best_model_match.to_s
|
230
|
+
ActiveFedora.model_mapper.classifier(resource).best_model
|
218
231
|
end
|
219
232
|
|
220
233
|
def equivalent_class?(other_class)
|
@@ -276,9 +289,9 @@ module ActiveFedora
|
|
276
289
|
def field_name_for(key)
|
277
290
|
if @klass.delegated_attributes.key?(key)
|
278
291
|
# TODO: Check to see if `key' is a possible solr field for this class, if it isn't try :searchable instead
|
279
|
-
ActiveFedora
|
292
|
+
ActiveFedora.index_field_mapper.solr_name(key, :stored_searchable, type: :string)
|
280
293
|
elsif key == :id
|
281
|
-
|
294
|
+
ActiveFedora.id_field
|
282
295
|
else
|
283
296
|
key.to_s
|
284
297
|
end
|
@@ -3,6 +3,14 @@ module ActiveFedora
|
|
3
3
|
module Default
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
+
included do
|
7
|
+
class_attribute :default_scopes, instance_writer: false, instance_predicate: false
|
8
|
+
class_attribute :default_scope_override, instance_writer: false, instance_predicate: false
|
9
|
+
|
10
|
+
self.default_scopes = []
|
11
|
+
self.default_scope_override = nil
|
12
|
+
end
|
13
|
+
|
6
14
|
module ClassMethods
|
7
15
|
# Returns a scope for the model without the +default_scope+.
|
8
16
|
#
|
@@ -32,6 +40,111 @@ module ActiveFedora
|
|
32
40
|
def unscoped
|
33
41
|
block_given? ? relation.scoping { yield } : relation
|
34
42
|
end
|
43
|
+
|
44
|
+
# Are there attributes associated with this scope?
|
45
|
+
def scope_attributes? # :nodoc:
|
46
|
+
super || default_scopes.any? || respond_to?(:default_scope)
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
# Use this macro in your model to set a default scope for all operations on
|
52
|
+
# the model.
|
53
|
+
#
|
54
|
+
# class Article < ActiveRecord::Base
|
55
|
+
# default_scope { where(published: true) }
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# Article.all # => SELECT * FROM articles WHERE published = true
|
59
|
+
#
|
60
|
+
# The #default_scope is also applied while creating/building a record.
|
61
|
+
# It is not applied while updating a record.
|
62
|
+
#
|
63
|
+
# Article.new.published # => true
|
64
|
+
# Article.create.published # => true
|
65
|
+
#
|
66
|
+
# (You can also pass any object which responds to +call+ to the
|
67
|
+
# +default_scope+ macro, and it will be called when building the
|
68
|
+
# default scope.)
|
69
|
+
#
|
70
|
+
# If you use multiple #default_scope declarations in your model then
|
71
|
+
# they will be merged together:
|
72
|
+
#
|
73
|
+
# class Article < ActiveRecord::Base
|
74
|
+
# default_scope { where(published: true) }
|
75
|
+
# default_scope { where(rating: 'G') }
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
|
79
|
+
#
|
80
|
+
# This is also the case with inheritance and module includes where the
|
81
|
+
# parent or module defines a #default_scope and the child or including
|
82
|
+
# class defines a second one.
|
83
|
+
#
|
84
|
+
# If you need to do more complex things with a default scope, you can
|
85
|
+
# alternatively define it as a class method:
|
86
|
+
#
|
87
|
+
# class Article < ActiveRecord::Base
|
88
|
+
# def self.default_scope
|
89
|
+
# # Should return a scope, you can call 'super' here etc.
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
def default_scope(scope = nil)
|
93
|
+
scope = Proc.new if block_given?
|
94
|
+
|
95
|
+
if scope.is_a?(Relation) || !scope.respond_to?(:call)
|
96
|
+
raise ArgumentError,
|
97
|
+
"Support for calling #default_scope without a block is removed. For example instead " \
|
98
|
+
"of `default_scope where(color: 'red')`, please use " \
|
99
|
+
"`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
|
100
|
+
"self.default_scope.)"
|
101
|
+
end
|
102
|
+
|
103
|
+
self.default_scopes += [scope]
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_default_scope(base_rel = nil) # :nodoc:
|
107
|
+
return if abstract_class?
|
108
|
+
|
109
|
+
if default_scope_override.nil?
|
110
|
+
self.default_scope_override = !Base.is_a?(method(:default_scope).owner)
|
111
|
+
end
|
112
|
+
|
113
|
+
if default_scope_override
|
114
|
+
# The user has defined their own default scope method, so call that
|
115
|
+
evaluate_default_scope { default_scope }
|
116
|
+
elsif default_scopes.any?
|
117
|
+
base_rel ||= relation
|
118
|
+
evaluate_default_scope do
|
119
|
+
default_scopes.inject(base_rel) do |default_scope, scope|
|
120
|
+
scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
|
121
|
+
default_scope.merge(base_rel.instance_exec(&scope))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def ignore_default_scope? # :nodoc:
|
128
|
+
Thread.current["#{self}_ignore_default_scope"]
|
129
|
+
end
|
130
|
+
|
131
|
+
def ignore_default_scope=(ignore) # :nodoc:
|
132
|
+
Thread.current["#{self}_ignore_default_scope"] = ignore
|
133
|
+
end
|
134
|
+
|
135
|
+
# The ignore_default_scope flag is used to prevent an infinite recursion
|
136
|
+
# situation where a default scope references a scope which has a default
|
137
|
+
# scope which references a scope...
|
138
|
+
def evaluate_default_scope # :nodoc:
|
139
|
+
return if ignore_default_scope?
|
140
|
+
|
141
|
+
begin
|
142
|
+
self.ignore_default_scope = true
|
143
|
+
yield
|
144
|
+
ensure
|
145
|
+
self.ignore_default_scope = false
|
146
|
+
end
|
147
|
+
end
|
35
148
|
end
|
36
149
|
end
|
37
150
|
end
|