all_futures 1.0.3 → 2.0.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/Gemfile +4 -1
- data/Gemfile.lock +272 -61
- data/LICENSE.txt +1 -1
- data/README.md +59 -79
- data/Rakefile +13 -1
- data/SUMMARY.md +22 -2
- data/bin/console +8 -0
- data/bin/loc +0 -0
- data/bin/setup +0 -0
- data/bin/standardize +0 -0
- data/lib/all_futures/association.rb +42 -0
- data/lib/all_futures/association_index.rb +69 -0
- data/lib/all_futures/attributes.rb +28 -0
- data/lib/all_futures/base.rb +66 -0
- data/lib/all_futures/callbacks.rb +71 -0
- data/lib/all_futures/configuration.rb +9 -0
- data/lib/all_futures/dirty.rb +116 -0
- data/lib/all_futures/embeds.rb +40 -0
- data/lib/all_futures/errors.rb +37 -0
- data/lib/all_futures/finder.rb +214 -0
- data/lib/all_futures/locale/en.yml +49 -0
- data/lib/all_futures/persistence.rb +595 -0
- data/lib/all_futures/presenter.rb +35 -0
- data/lib/all_futures/railtie.rb +26 -0
- data/lib/all_futures/translation.rb +22 -0
- data/lib/all_futures/validations.rb +10 -0
- data/lib/all_futures/version.rb +3 -1
- data/lib/all_futures/versions.rb +80 -0
- data/lib/all_futures.rb +24 -1
- data/lib/vendor/ACTIVE_ENTITY_MIT-LICENSE +42 -0
- data/lib/vendor/README.md +8 -0
- data/lib/vendor/active_entity/aggregations.rb +277 -0
- data/lib/vendor/active_entity/associations/embeds/association.rb +134 -0
- data/lib/vendor/active_entity/associations/embeds/builder/association.rb +105 -0
- data/lib/vendor/active_entity/associations/embeds/builder/collection_association.rb +71 -0
- data/lib/vendor/active_entity/associations/embeds/builder/embedded_in.rb +38 -0
- data/lib/vendor/active_entity/associations/embeds/builder/embeds_many.rb +13 -0
- data/lib/vendor/active_entity/associations/embeds/builder/embeds_one.rb +16 -0
- data/lib/vendor/active_entity/associations/embeds/builder/singular_association.rb +28 -0
- data/lib/vendor/active_entity/associations/embeds/collection_association.rb +209 -0
- data/lib/vendor/active_entity/associations/embeds/collection_proxy.rb +310 -0
- data/lib/vendor/active_entity/associations/embeds/embedded_in_association.rb +31 -0
- data/lib/vendor/active_entity/associations/embeds/embeds_many_association.rb +15 -0
- data/lib/vendor/active_entity/associations/embeds/embeds_one_association.rb +26 -0
- data/lib/vendor/active_entity/associations/embeds/singular_association.rb +35 -0
- data/lib/vendor/active_entity/associations.rb +168 -0
- data/lib/vendor/active_entity/attribute_assignment.rb +87 -0
- data/lib/vendor/active_entity/attribute_decorators.rb +90 -0
- data/lib/vendor/active_entity/attribute_methods/before_type_cast.rb +78 -0
- data/lib/vendor/active_entity/attribute_methods/dirty.rb +180 -0
- data/lib/vendor/active_entity/attribute_methods/primary_key.rb +96 -0
- data/lib/vendor/active_entity/attribute_methods/query.rb +38 -0
- data/lib/vendor/active_entity/attribute_methods/read.rb +44 -0
- data/lib/vendor/active_entity/attribute_methods/serialization.rb +90 -0
- data/lib/vendor/active_entity/attribute_methods/time_zone_conversion.rb +93 -0
- data/lib/vendor/active_entity/attribute_methods/write.rb +54 -0
- data/lib/vendor/active_entity/attribute_methods.rb +833 -0
- data/lib/vendor/active_entity/attributes.rb +240 -0
- data/lib/vendor/active_entity/base.rb +293 -0
- data/lib/vendor/active_entity/callbacks.rb +21 -0
- data/lib/vendor/active_entity/coders/json.rb +15 -0
- data/lib/vendor/active_entity/coders/yaml_column.rb +50 -0
- data/lib/vendor/active_entity/core.rb +348 -0
- data/lib/vendor/active_entity/enum.rb +260 -0
- data/lib/vendor/active_entity/errors.rb +69 -0
- data/lib/vendor/active_entity/gem_version.rb +17 -0
- data/lib/vendor/active_entity/inheritance.rb +176 -0
- data/lib/vendor/active_entity/integration.rb +78 -0
- data/lib/vendor/active_entity/locale/en.yml +45 -0
- data/lib/vendor/active_entity/model_schema.rb +118 -0
- data/lib/vendor/active_entity/nested_attributes.rb +554 -0
- data/lib/vendor/active_entity/persistence.rb +20 -0
- data/lib/vendor/active_entity/railtie.rb +76 -0
- data/lib/vendor/active_entity/readonly_attributes.rb +55 -0
- data/lib/vendor/active_entity/reflection.rb +447 -0
- data/lib/vendor/active_entity/serialization.rb +28 -0
- data/lib/vendor/active_entity/store.rb +291 -0
- data/lib/vendor/active_entity/translation.rb +24 -0
- data/lib/vendor/active_entity/type/date.rb +9 -0
- data/lib/vendor/active_entity/type/date_time.rb +9 -0
- data/lib/vendor/active_entity/type/internal/timezone.rb +17 -0
- data/lib/vendor/active_entity/type/json.rb +30 -0
- data/lib/vendor/active_entity/type/modifiers/array.rb +72 -0
- data/lib/vendor/active_entity/type/modifiers/array_without_blank.rb +19 -0
- data/lib/vendor/active_entity/type/registry.rb +112 -0
- data/lib/vendor/active_entity/type/serialized.rb +71 -0
- data/lib/vendor/active_entity/type/text.rb +11 -0
- data/lib/vendor/active_entity/type/time.rb +21 -0
- data/lib/vendor/active_entity/type/unsigned_integer.rb +17 -0
- data/lib/vendor/active_entity/type.rb +75 -0
- data/lib/vendor/active_entity/validate_embeds_association.rb +300 -0
- data/lib/vendor/active_entity/validations/absence.rb +25 -0
- data/lib/vendor/active_entity/validations/associated.rb +60 -0
- data/lib/vendor/active_entity/validations/length.rb +26 -0
- data/lib/vendor/active_entity/validations/presence.rb +68 -0
- data/lib/vendor/active_entity/validations/subset.rb +76 -0
- data/lib/vendor/active_entity/validations/uniqueness_in_embeds.rb +91 -0
- data/lib/vendor/active_entity/validations/uniqueness_on_active_record.rb +234 -0
- data/lib/vendor/active_entity/validations.rb +47 -0
- data/lib/vendor/active_entity/version.rb +10 -0
- data/lib/vendor/active_entity.rb +99 -0
- data/lib/vendor/core_ext/array_without_blank.rb +48 -0
- metadata +175 -21
- data/lib/all_futures/all_futures.rb +0 -28
- data/lib/all_futures/config.rb +0 -14
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
|
4
|
+
|
|
5
|
+
module ActiveEntity
|
|
6
|
+
# == Single table inheritance
|
|
7
|
+
#
|
|
8
|
+
# Active Entity allows inheritance by storing the name of the class in a column that by
|
|
9
|
+
# default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
|
|
10
|
+
# This means that an inheritance looking like this:
|
|
11
|
+
#
|
|
12
|
+
# class Company < ActiveEntity::Base; end
|
|
13
|
+
# class Firm < Company; end
|
|
14
|
+
# class Client < Company; end
|
|
15
|
+
# class PriorityClient < Client; end
|
|
16
|
+
#
|
|
17
|
+
# When you do <tt>Firm.create(name: "37signals")</tt>, this record will be saved in
|
|
18
|
+
# the companies table with type = "Firm". You can then fetch this row again using
|
|
19
|
+
# <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
|
|
20
|
+
#
|
|
21
|
+
# Be aware that because the type column is an attribute on the record every new
|
|
22
|
+
# subclass will instantly be marked as dirty and the type column will be included
|
|
23
|
+
# in the list of changed attributes on the record. This is different from non
|
|
24
|
+
# Single Table Inheritance(STI) classes:
|
|
25
|
+
#
|
|
26
|
+
# Company.new.changed? # => false
|
|
27
|
+
# Firm.new.changed? # => true
|
|
28
|
+
# Firm.new.changes # => {"type"=>["","Firm"]}
|
|
29
|
+
#
|
|
30
|
+
# If you don't have a type column defined in your table, single-table inheritance won't
|
|
31
|
+
# be triggered. In that case, it'll work just like normal subclasses with no special magic
|
|
32
|
+
# for differentiating between them or reloading the right type with find.
|
|
33
|
+
#
|
|
34
|
+
# Note, all the attributes for all the cases are kept in the same table. Read more:
|
|
35
|
+
# https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
|
|
36
|
+
#
|
|
37
|
+
module Inheritance
|
|
38
|
+
extend ActiveSupport::Concern
|
|
39
|
+
|
|
40
|
+
module ClassMethods
|
|
41
|
+
# Determines if one of the attributes passed in is the inheritance column,
|
|
42
|
+
# and if the inheritance column is attr accessible, it initializes an
|
|
43
|
+
# instance of the given subclass instead of the base class.
|
|
44
|
+
def new(attributes = nil, &block)
|
|
45
|
+
if abstract_class? || self == Base
|
|
46
|
+
raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
super
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns +true+ if this does not need STI type condition. Returns
|
|
53
|
+
# +false+ if STI type condition needs to be applied.
|
|
54
|
+
def descends_from_active_entity?
|
|
55
|
+
if self == Base
|
|
56
|
+
false
|
|
57
|
+
elsif superclass.abstract_class?
|
|
58
|
+
superclass.descends_from_active_entity?
|
|
59
|
+
else
|
|
60
|
+
superclass == Base
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns the class descending directly from ActiveEntity::Base, or
|
|
65
|
+
# an abstract class, if any, in the inheritance hierarchy.
|
|
66
|
+
#
|
|
67
|
+
# If A extends ActiveEntity::Base, A.base_class will return A. If B descends from A
|
|
68
|
+
# through some arbitrarily deep hierarchy, B.base_class will return A.
|
|
69
|
+
#
|
|
70
|
+
# If B < A and C < B and if A is an abstract_class then both B.base_class
|
|
71
|
+
# and C.base_class would return B as the answer since A is an abstract_class.
|
|
72
|
+
def base_class
|
|
73
|
+
unless self < Base
|
|
74
|
+
raise ActiveEntityError, "#{name} doesn't belong in a hierarchy descending from ActiveEntity"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if superclass == Base || superclass.abstract_class?
|
|
78
|
+
self
|
|
79
|
+
else
|
|
80
|
+
superclass.base_class
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Returns whether the class is a base class.
|
|
85
|
+
# See #base_class for more information.
|
|
86
|
+
def base_class?
|
|
87
|
+
base_class == self
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Set this to +true+ if this is an abstract class (see
|
|
91
|
+
# <tt>abstract_class?</tt>).
|
|
92
|
+
# If you are using inheritance with Active Entity and don't want a class
|
|
93
|
+
# to be considered as part of the STI hierarchy, you must set this to
|
|
94
|
+
# true.
|
|
95
|
+
# +ApplicationRecord+, for example, is generated as an abstract class.
|
|
96
|
+
#
|
|
97
|
+
# Consider the following default behaviour:
|
|
98
|
+
#
|
|
99
|
+
# Shape = Class.new(ActiveEntity::Base)
|
|
100
|
+
# Polygon = Class.new(Shape)
|
|
101
|
+
# Square = Class.new(Polygon)
|
|
102
|
+
#
|
|
103
|
+
# Shape.table_name # => "shapes"
|
|
104
|
+
# Polygon.table_name # => "shapes"
|
|
105
|
+
# Square.table_name # => "shapes"
|
|
106
|
+
# Shape.create! # => #<Shape id: 1, type: nil>
|
|
107
|
+
# Polygon.create! # => #<Polygon id: 2, type: "Polygon">
|
|
108
|
+
# Square.create! # => #<Square id: 3, type: "Square">
|
|
109
|
+
#
|
|
110
|
+
# However, when using <tt>abstract_class</tt>, +Shape+ is omitted from
|
|
111
|
+
# the hierarchy:
|
|
112
|
+
#
|
|
113
|
+
# class Shape < ActiveEntity::Base
|
|
114
|
+
# self.abstract_class = true
|
|
115
|
+
# end
|
|
116
|
+
# Polygon = Class.new(Shape)
|
|
117
|
+
# Square = Class.new(Polygon)
|
|
118
|
+
#
|
|
119
|
+
# Shape.table_name # => nil
|
|
120
|
+
# Polygon.table_name # => "polygons"
|
|
121
|
+
# Square.table_name # => "polygons"
|
|
122
|
+
# Shape.create! # => NotImplementedError: Shape is an abstract class and cannot be instantiated.
|
|
123
|
+
# Polygon.create! # => #<Polygon id: 1, type: nil>
|
|
124
|
+
# Square.create! # => #<Square id: 2, type: "Square">
|
|
125
|
+
#
|
|
126
|
+
# Note that in the above example, to disallow the creation of a plain
|
|
127
|
+
# +Polygon+, you should use <tt>validates :type, presence: true</tt>,
|
|
128
|
+
# instead of setting it as an abstract class. This way, +Polygon+ will
|
|
129
|
+
# stay in the hierarchy, and Active Entity will continue to correctly
|
|
130
|
+
# derive the table name.
|
|
131
|
+
attr_accessor :abstract_class
|
|
132
|
+
|
|
133
|
+
# Returns whether this class is an abstract class or not.
|
|
134
|
+
def abstract_class?
|
|
135
|
+
defined?(@abstract_class) && @abstract_class == true
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def inherited(subclass)
|
|
139
|
+
subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
|
|
140
|
+
super
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
protected
|
|
144
|
+
|
|
145
|
+
# Returns the class type of the record using the current module as a prefix. So descendants of
|
|
146
|
+
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
|
|
147
|
+
def compute_type(type_name)
|
|
148
|
+
if type_name.start_with?("::")
|
|
149
|
+
# If the type is prefixed with a scope operator then we assume that
|
|
150
|
+
# the type_name is an absolute reference.
|
|
151
|
+
ActiveSupport::Dependencies.constantize(type_name)
|
|
152
|
+
else
|
|
153
|
+
type_candidate = @_type_candidates_cache[type_name]
|
|
154
|
+
if type_candidate && type_constant = type_candidate.safe_constantize
|
|
155
|
+
return type_constant
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Build a list of candidates to search for
|
|
159
|
+
candidates = []
|
|
160
|
+
name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
|
|
161
|
+
candidates << type_name
|
|
162
|
+
|
|
163
|
+
candidates.each do |candidate|
|
|
164
|
+
constant = candidate.safe_constantize
|
|
165
|
+
if candidate == constant.to_s
|
|
166
|
+
@_type_candidates_cache[type_name] = candidate
|
|
167
|
+
return constant
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/string/filters"
|
|
4
|
+
|
|
5
|
+
module ActiveEntity
|
|
6
|
+
module Integration
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
# Returns a +String+, which Action Pack uses for constructing a URL to this
|
|
10
|
+
# object. The default implementation returns this record's id as a +String+,
|
|
11
|
+
# or +nil+ if this record's unsaved.
|
|
12
|
+
#
|
|
13
|
+
# For example, suppose that you have a User model, and that you have a
|
|
14
|
+
# <tt>resources :users</tt> route. Normally, +user_path+ will
|
|
15
|
+
# construct a path with the user object's 'id' in it:
|
|
16
|
+
#
|
|
17
|
+
# user = User.find_by(name: 'Phusion')
|
|
18
|
+
# user_path(user) # => "/users/1"
|
|
19
|
+
#
|
|
20
|
+
# You can override +to_param+ in your model to make +user_path+ construct
|
|
21
|
+
# a path using the user's name instead of the user's id:
|
|
22
|
+
#
|
|
23
|
+
# class User < ActiveEntity::Base
|
|
24
|
+
# def to_param # overridden
|
|
25
|
+
# name
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# user = User.find_by(name: 'Phusion')
|
|
30
|
+
# user_path(user) # => "/users/Phusion"
|
|
31
|
+
def to_param
|
|
32
|
+
# We can't use alias_method here, because method 'id' optimizes itself on the fly.
|
|
33
|
+
id&.to_s # Be sure to stringify the id for routes
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module ClassMethods
|
|
37
|
+
# Defines your model's +to_param+ method to generate "pretty" URLs
|
|
38
|
+
# using +method_name+, which can be any attribute or method that
|
|
39
|
+
# responds to +to_s+.
|
|
40
|
+
#
|
|
41
|
+
# class User < ActiveEntity::Base
|
|
42
|
+
# to_param :name
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# user = User.find_by(name: 'Fancy Pants')
|
|
46
|
+
# user.id # => 123
|
|
47
|
+
# user_path(user) # => "/users/123-fancy-pants"
|
|
48
|
+
#
|
|
49
|
+
# Values longer than 20 characters will be truncated. The value
|
|
50
|
+
# is truncated word by word.
|
|
51
|
+
#
|
|
52
|
+
# user = User.find_by(name: 'David Heinemeier Hansson')
|
|
53
|
+
# user.id # => 125
|
|
54
|
+
# user_path(user) # => "/users/125-david-heinemeier"
|
|
55
|
+
#
|
|
56
|
+
# Because the generated param begins with the record's +id+, it is
|
|
57
|
+
# suitable for passing to +find+. In a controller, for example:
|
|
58
|
+
#
|
|
59
|
+
# params[:id] # => "123-fancy-pants"
|
|
60
|
+
# User.find(params[:id]).id # => 123
|
|
61
|
+
def to_param(method_name = nil)
|
|
62
|
+
if method_name.nil?
|
|
63
|
+
super()
|
|
64
|
+
else
|
|
65
|
+
define_method :to_param do
|
|
66
|
+
if (default = super()) &&
|
|
67
|
+
(result = send(method_name).to_s).present? &&
|
|
68
|
+
(param = result.squish.parameterize.truncate(20, separator: /-/, omission: "")).present?
|
|
69
|
+
"#{default}-#{param}"
|
|
70
|
+
else
|
|
71
|
+
default
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
en:
|
|
2
|
+
# Attributes names common to most models
|
|
3
|
+
#attributes:
|
|
4
|
+
#created_at: "Created at"
|
|
5
|
+
#updated_at: "Updated at"
|
|
6
|
+
|
|
7
|
+
# Default error messages
|
|
8
|
+
errors:
|
|
9
|
+
messages:
|
|
10
|
+
non_subset: "is not subset of the given list"
|
|
11
|
+
duplicated: "duplicated"
|
|
12
|
+
|
|
13
|
+
# Active Entity models configuration
|
|
14
|
+
active_entity:
|
|
15
|
+
errors:
|
|
16
|
+
messages:
|
|
17
|
+
record_invalid: "Validation failed: %{errors}"
|
|
18
|
+
# Append your own errors here or at the model/attributes scope.
|
|
19
|
+
|
|
20
|
+
# You can define own errors for models or model attributes.
|
|
21
|
+
# The values :model, :attribute and :value are always available for interpolation.
|
|
22
|
+
#
|
|
23
|
+
# For example,
|
|
24
|
+
# models:
|
|
25
|
+
# user:
|
|
26
|
+
# blank: "This is a custom blank message for %{model}: %{attribute}"
|
|
27
|
+
# attributes:
|
|
28
|
+
# login:
|
|
29
|
+
# blank: "This is a custom blank message for User login"
|
|
30
|
+
# Will define custom blank validation message for User model and
|
|
31
|
+
# custom blank validation message for login attribute of User model.
|
|
32
|
+
#models:
|
|
33
|
+
|
|
34
|
+
# Translate model names. Used in Model.human_name().
|
|
35
|
+
#models:
|
|
36
|
+
# For example,
|
|
37
|
+
# user: "Dude"
|
|
38
|
+
# will translate User model name to "Dude"
|
|
39
|
+
|
|
40
|
+
# Translate model attribute names. Used in Model.human_attribute_name(attribute).
|
|
41
|
+
#attributes:
|
|
42
|
+
# For example,
|
|
43
|
+
# user:
|
|
44
|
+
# login: "Handle"
|
|
45
|
+
# will translate User attribute "login" as "Handle"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "monitor"
|
|
4
|
+
|
|
5
|
+
module ActiveEntity
|
|
6
|
+
module ModelSchema
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
delegate :type_for_attribute, to: :class
|
|
11
|
+
|
|
12
|
+
initialize_load_schema_monitor
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods
|
|
16
|
+
def attributes_builder # :nodoc:
|
|
17
|
+
unless defined?(@attributes_builder) && @attributes_builder
|
|
18
|
+
defaults = _default_attributes
|
|
19
|
+
@attributes_builder = ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
|
|
20
|
+
end
|
|
21
|
+
@attributes_builder
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def attribute_types # :nodoc:
|
|
25
|
+
load_schema
|
|
26
|
+
@attribute_types ||= Hash.new(Type.default_value)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def yaml_encoder # :nodoc:
|
|
30
|
+
@yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the type of the attribute with the given name, after applying
|
|
34
|
+
# all modifiers. This method is the only valid source of information for
|
|
35
|
+
# anything related to the types of a model's attributes. This method will
|
|
36
|
+
# access the database and load the model's schema if it is required.
|
|
37
|
+
#
|
|
38
|
+
# The return value of this method will implement the interface described
|
|
39
|
+
# by ActiveModel::Type::Value (though the object itself may not subclass
|
|
40
|
+
# it).
|
|
41
|
+
#
|
|
42
|
+
# +attr_name+ The name of the attribute to retrieve the type for. Must be
|
|
43
|
+
# a string or a symbol.
|
|
44
|
+
def type_for_attribute(attr_name, &block)
|
|
45
|
+
attr_name = attr_name.to_s
|
|
46
|
+
if block
|
|
47
|
+
attribute_types.fetch(attr_name, &block)
|
|
48
|
+
else
|
|
49
|
+
attribute_types[attr_name]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def _default_attributes # :nodoc:
|
|
54
|
+
load_schema
|
|
55
|
+
@default_attributes ||= ActiveModel::AttributeSet.new({})
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
protected
|
|
59
|
+
|
|
60
|
+
def initialize_load_schema_monitor
|
|
61
|
+
@load_schema_monitor = Monitor.new
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def inherited(child_class)
|
|
67
|
+
super
|
|
68
|
+
child_class.initialize_load_schema_monitor
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def schema_loaded?
|
|
72
|
+
defined?(@schema_loaded) && @schema_loaded
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def load_schema
|
|
76
|
+
return if schema_loaded?
|
|
77
|
+
@load_schema_monitor.synchronize do
|
|
78
|
+
return if defined?(@load_schema_invoked) && @load_schema_invoked
|
|
79
|
+
|
|
80
|
+
load_schema!
|
|
81
|
+
@schema_loaded = true
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def load_schema!
|
|
86
|
+
@load_schema_invoked = true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if ActiveSupport::VERSION::MAJOR >= 7
|
|
90
|
+
def reload_schema_from_cache
|
|
91
|
+
@attribute_types = nil
|
|
92
|
+
@default_attributes = nil
|
|
93
|
+
@attributes_builder = nil
|
|
94
|
+
@schema_loaded = false
|
|
95
|
+
@load_schema_invoked = false
|
|
96
|
+
@attribute_names = nil
|
|
97
|
+
@yaml_encoder = nil
|
|
98
|
+
subclasses.each do |descendant|
|
|
99
|
+
descendant.send(:reload_schema_from_cache)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
def reload_schema_from_cache
|
|
104
|
+
@attribute_types = nil
|
|
105
|
+
@default_attributes = nil
|
|
106
|
+
@attributes_builder = nil
|
|
107
|
+
@schema_loaded = false
|
|
108
|
+
@load_schema_invoked = false
|
|
109
|
+
@attribute_names = nil
|
|
110
|
+
@yaml_encoder = nil
|
|
111
|
+
direct_descendants.each do |descendant|
|
|
112
|
+
descendant.send(:reload_schema_from_cache)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|