目的: どのようにバリデーションが定義されているかを知る
class Story < ApplicationRecord
TraceLocation.trace(format: :markdown) do
validates :title, allow_blank: true, length: { in: 1..65_535 }
end
end
Generated by trace_location at 2019-06-03 23:50:02 +0900
activemodel-5.2.3/lib/active_model/validations/validates.rb:105
def validates(*attributes)
defaults = attributes.extract_options!.dup
validations = defaults.slice!(*_validates_default_keys)
raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
raise ArgumentError, "You need to supply at least one validation" if validations.empty?
defaults[:attributes] = attributes
validations.each do |key, options|
next unless options
key = "#{key.to_s.camelize}Validator"
begin
validator = key.include?("::".freeze) ? key.constantize : const_get(key)
rescue NameError
raise ArgumentError, "Unknown validator: '#{key}'"
end
validates_with(validator, defaults.merge(_parse_validates_options(options)))
end
end
# called from /path/to/sample-app/app/models/story.rb:38
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:24
def extract_options!
if last.is_a?(Hash) && last.extractable_options?
pop
else
{}
end
end
# called from activemodel-5.2.3/lib/active_model/validations/validates.rb:106
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:9
def extractable_options?
instance_of?(Hash)
end
# called from activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:25
activemodel-5.2.3/lib/active_model/validations/validates.rb:156
def _validates_default_keys
[:if, :unless, :on, :allow_blank, :allow_nil, :strict]
end
# called from activemodel-5.2.3/lib/active_model/validations/validates.rb:107
activesupport-5.2.3/lib/active_support/core_ext/hash/slice.rb:32
def slice!(*keys)
omit = slice(*self.keys - keys)
hash = slice(*keys)
hash.default = default
hash.default_proc = default_proc if default_proc
replace(hash)
omit
end
# called from activemodel-5.2.3/lib/active_model/validations/validates.rb:107
activesupport-5.2.3/lib/active_support/core_ext/string/inflections.rb:91
def camelize(first_letter = :upper)
case first_letter
when :upper
ActiveSupport::Inflector.camelize(self, true)
when :lower
ActiveSupport::Inflector.camelize(self, false)
else
raise ArgumentError, "Invalid option, use either :upper or :lower."
end
end
# called from activemodel-5.2.3/lib/active_model/validations/validates.rb:116
activesupport-5.2.3/lib/active_support/inflector/methods.rb:69
def camelize(term, uppercase_first_letter = true)
string = term.to_s
if uppercase_first_letter
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
else
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase }
end
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
string.gsub!("/".freeze, "::".freeze)
string
end
# called from activesupport-5.2.3/lib/active_support/core_ext/string/inflections.rb:94
activesupport-5.2.3/lib/active_support/inflector/inflections.rb:252
def inflections(locale = :en)
if block_given?
yield Inflections.instance(locale)
else
Inflections.instance(locale)
end
end
# called from activesupport-5.2.3/lib/active_support/inflector/methods.rb:72
activesupport-5.2.3/lib/active_support/inflector/inflections.rb:66
def self.instance(locale = :en)
@__instance__[locale] ||= new
end
# called from activesupport-5.2.3/lib/active_support/inflector/inflections.rb:256
concurrent-ruby-1.1.5/lib/concurrent/map.rb:132
def [](key)
if value = super # non-falsy value is an existing mapping, return it right away
value
# re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
# a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value
# would be returned)
# note: nil == value check is not technically necessary
elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
@default_proc.call(self, key)
else
value
end
end
# called from activesupport-5.2.3/lib/active_support/inflector/inflections.rb:67
concurrent-ruby-1.1.5/lib/concurrent/collection/map/non_concurrent_map_backend.rb:19
def [](key)
@backend[key]
end
# called from concurrent-ruby-1.1.5/lib/concurrent/map.rb:133
activemodel-5.2.3/lib/active_model/validations/validates.rb:160
def _parse_validates_options(options)
case options
when TrueClass
{}
when Hash
options
when Range, Array
{ in: options }
else
{ with: options }
end
end
# called from activemodel-5.2.3/lib/active_model/validations/validates.rb:124
activemodel-5.2.3/lib/active_model/validations/with.rb:81
def validates_with(*args, &block)
options = args.extract_options!
options[:class] = self
args.each do |klass|
validator = klass.new(options, &block)
if validator.respond_to?(:attributes) && !validator.attributes.empty?
validator.attributes.each do |attribute|
_validators[attribute.to_sym] << validator
end
else
_validators[nil] << validator
end
validate(validator, options)
end
end
# called from activemodel-5.2.3/lib/active_model/validations/validates.rb:124
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:24
def extract_options!
if last.is_a?(Hash) && last.extractable_options?
pop
else
{}
end
end
# called from activemodel-5.2.3/lib/active_model/validations/with.rb:82
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:9
def extractable_options?
instance_of?(Hash)
end
# called from activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:25
activemodel-5.2.3/lib/active_model/validations/length.rb:11
def initialize(options)
if range = (options.delete(:in) || options.delete(:within))
raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
options[:minimum], options[:maximum] = range.min, range.max
end
if options[:allow_blank] == false && options[:minimum].nil? && options[:is].nil?
options[:minimum] = 1
end
super
end
# called from activemodel-5.2.3/lib/active_model/validations/with.rb:86
activemodel-5.2.3/lib/active_model/validator.rb:138
def initialize(options)
@attributes = Array(options.delete(:attributes))
raise ArgumentError, ":attributes cannot be blank" if @attributes.empty?
super
check_validity!
end
# called from activemodel-5.2.3/lib/active_model/validations/length.rb:21
activemodel-5.2.3/lib/active_model/validator.rb:108
def initialize(options = {})
@options = options.except(:class).freeze
end
# called from activemodel-5.2.3/lib/active_model/validator.rb:141
activesupport-5.2.3/lib/active_support/core_ext/hash/except.rb:12
def except(*keys)
dup.except!(*keys)
end
# called from activemodel-5.2.3/lib/active_model/validator.rb:109
activesupport-5.2.3/lib/active_support/core_ext/hash/except.rb:20
def except!(*keys)
keys.each { |key| delete(key) }
self
end
# called from activesupport-5.2.3/lib/active_support/core_ext/hash/except.rb:13
activemodel-5.2.3/lib/active_model/validations/length.rb:24
def check_validity!
keys = CHECKS.keys & options.keys
if keys.empty?
raise ArgumentError, "Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option."
end
keys.each do |key|
value = options[key]
unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY || value.is_a?(Symbol) || value.is_a?(Proc)
raise ArgumentError, ":#{key} must be a nonnegative Integer, Infinity, Symbol, or Proc"
end
end
end
# called from activemodel-5.2.3/lib/active_model/validator.rb:142
activesupport-5.2.3/lib/active_support/core_ext/class/attribute.rb:106
redefine_method(name) { val }
# called from activemodel-5.2.3/lib/active_model/validations/with.rb:90
activemodel-5.2.3/lib/active_model/validations.rb:154
def validate(*args, &block)
options = args.extract_options!
if args.all? { |arg| arg.is_a?(Symbol) }
options.each_key do |k|
unless VALID_OPTIONS_FOR_VALIDATE.include?(k)
raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{VALID_OPTIONS_FOR_VALIDATE.map(&:inspect).join(', ')}. Perhaps you meant to call `validates` instead of `validate`?")
end
end
end
if options.key?(:on)
options = options.dup
options[:on] = Array(options[:on])
options[:if] = Array(options[:if])
options[:if].unshift ->(o) {
!(options[:on] & Array(o.validation_context)).empty?
}
end
set_callback(:validate, *args, options, &block)
end
# called from activemodel-5.2.3/lib/active_model/validations/with.rb:96
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:24
def extract_options!
if last.is_a?(Hash) && last.extractable_options?
pop
else
{}
end
end
# called from activemodel-5.2.3/lib/active_model/validations.rb:155
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:9
def extractable_options?
instance_of?(Hash)
end
# called from activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:25
activesupport-5.2.3/lib/active_support/callbacks.rb:667
def set_callback(name, *filter_list, &block)
type, filters, options = normalize_callback_params(filter_list, block)
self_chain = get_callbacks name
mapped = filters.map do |filter|
Callback.build(self_chain, filter, type, options)
end
__update_callbacks(name) do |target, chain|
options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
target.set_callbacks name, chain
end
end
# called from activemodel-5.2.3/lib/active_model/validations.rb:174
activesupport-5.2.3/lib/active_support/callbacks.rb:615
def normalize_callback_params(filters, block) # :nodoc:
type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before
options = filters.extract_options!
filters.unshift(block) if block
[type, filters, options.dup]
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:668
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:24
def extract_options!
if last.is_a?(Hash) && last.extractable_options?
pop
else
{}
end
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:617
activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:9
def extractable_options?
instance_of?(Hash)
end
# called from activesupport-5.2.3/lib/active_support/core_ext/array/extract_options.rb:25
activesupport-5.2.3/lib/active_support/callbacks.rb:836
def get_callbacks(name) # :nodoc:
__callbacks[name.to_sym]
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:670
activesupport-5.2.3/lib/active_support/core_ext/class/attribute.rb:106
redefine_method(name) { val }
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:837
activesupport-5.2.3/lib/active_support/callbacks.rb:281
def self.build(chain, filter, kind, options)
if filter.is_a?(String)
raise ArgumentError, <<-MSG.squish
Passing string to define a callback is not supported. See the `.set_callback`
documentation to see supported values.
MSG
end
new chain.name, filter, kind, options, chain.config
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:672
activesupport-5.2.3/lib/active_support/callbacks.rb:295
def initialize(name, filter, kind, options, chain_config)
@chain_config = chain_config
@name = name
@kind = kind
@filter = filter
@key = compute_identifier filter
@if = check_conditionals(Array(options[:if]))
@unless = check_conditionals(Array(options[:unless]))
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:289
activesupport-5.2.3/lib/active_support/callbacks.rb:365
def compute_identifier(filter)
case filter
when ::Proc
filter.object_id
else
filter
end
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:300
activesupport-5.2.3/lib/active_support/callbacks.rb:353
def check_conditionals(conditionals)
if conditionals.any? { |c| c.is_a?(String) }
raise ArgumentError, <<-MSG.squish
Passing string to be evaluated in :if and :unless conditional
options is not supported. Pass a symbol for an instance method,
or a lambda, proc or block, instead.
MSG
end
conditionals
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:301
activesupport-5.2.3/lib/active_support/callbacks.rb:353
def check_conditionals(conditionals)
if conditionals.any? { |c| c.is_a?(String) }
raise ArgumentError, <<-MSG.squish
Passing string to be evaluated in :if and :unless conditional
options is not supported. Pass a symbol for an instance method,
or a lambda, proc or block, instead.
MSG
end
conditionals
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:302
activesupport-5.2.3/lib/active_support/callbacks.rb:624
def __update_callbacks(name) #:nodoc:
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target|
chain = target.get_callbacks name
yield target, chain.dup
end
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:675
activesupport-5.2.3/lib/active_support/descendants_tracker.rb:14
def descendants(klass)
arr = []
accumulate_descendants(klass, arr)
arr
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:625
activesupport-5.2.3/lib/active_support/descendants_tracker.rb:41
def accumulate_descendants(klass, acc)
if direct_descendants = @@direct_descendants[klass]
acc.concat(direct_descendants)
direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
end
end
# called from activesupport-5.2.3/lib/active_support/descendants_tracker.rb:16
activesupport-5.2.3/lib/active_support/callbacks.rb:836
def get_callbacks(name) # :nodoc:
__callbacks[name.to_sym]
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:626
activesupport-5.2.3/lib/active_support/core_ext/class/attribute.rb:106
redefine_method(name) { val }
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:837
activesupport-5.2.3/lib/active_support/callbacks.rb:557
def initialize_copy(other)
@callbacks = nil
@chain = other.chain.dup
@mutex = Mutex.new
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:627
activesupport-5.2.3/lib/active_support/callbacks.rb:581
def chain; @chain; end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:559
activesupport-5.2.3/lib/active_support/callbacks.rb:572
def append(*callbacks)
callbacks.each { |c| append_one(c) }
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:676
activesupport-5.2.3/lib/active_support/callbacks.rb:585
def append_one(callback)
@callbacks = nil
remove_duplicates(callback)
@chain.push(callback)
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:573
activesupport-5.2.3/lib/active_support/callbacks.rb:597
def remove_duplicates(callback)
@callbacks = nil
@chain.delete_if { |c| callback.duplicates?(c) }
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:587
activesupport-5.2.3/lib/active_support/callbacks.rb:324
def duplicates?(other)
case @filter
when Symbol
matches?(other.kind, other.filter)
else
false
end
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:599
activesupport-5.2.3/lib/active_support/callbacks.rb:840
def set_callbacks(name, callbacks) # :nodoc:
self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:677
activesupport-5.2.3/lib/active_support/core_ext/class/attribute.rb:106
redefine_method(name) { val }
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:841
activesupport-5.2.3/lib/active_support/core_ext/class/attribute.rb:104
define_singleton_method("#{name}=") do |val|
singleton_class.class_eval do
redefine_method(name) { val }
end
if singleton_class?
class_eval do
redefine_method(name) do
if instance_variable_defined? ivar
instance_variable_get ivar
else
singleton_class.send name
end
end
end
end
val
end
# called from activesupport-5.2.3/lib/active_support/callbacks.rb:841
activesupport-5.2.3/lib/active_support/core_ext/module/redefine_method.rb:26
def redefine_method(method, &block)
visibility = method_visibility(method)
silence_redefinition_of_method(method)
define_method(method, &block)
send(visibility, method)
end
# called from activesupport-5.2.3/lib/active_support/core_ext/class/attribute.rb:106
activesupport-5.2.3/lib/active_support/core_ext/module/redefine_method.rb:39
def method_visibility(method) # :nodoc:
case
when private_method_defined?(method)
:private
when protected_method_defined?(method)
:protected
else
:public
end
end
# called from activesupport-5.2.3/lib/active_support/core_ext/module/redefine_method.rb:27
activesupport-5.2.3/lib/active_support/core_ext/module/redefine_method.rb:8
def silence_redefinition_of_method(method)
if method_defined?(method) || private_method_defined?(method)
# This suppresses the "method redefined" warning; the self-alias
# looks odd, but means we don't need to generate a unique name
alias_method method, method
end
end
# called from activesupport-5.2.3/lib/active_support/core_ext/module/redefine_method.rb:28