active-fedora 9.9.1 → 9.10.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|