module ActiveRecord::Core
def self.application_record_class? # :nodoc:
def self.application_record_class? # :nodoc: if ActiveRecord.application_record_class self == ActiveRecord.application_record_class else if defined?(ApplicationRecord) && self == ApplicationRecord true end end end
def self.asynchronous_queries_session # :nodoc:
def self.asynchronous_queries_session # :nodoc: asynchronous_queries_tracker.current_session end
def self.asynchronous_queries_tracker # :nodoc:
def self.asynchronous_queries_tracker # :nodoc: ActiveSupport::IsolatedExecutionState[:active_record_asynchronous_queries_tracker] ||= \ AsynchronousQueriesTracker.new end
def self.configurations
def self.configurations @@configurations end
def self.configurations=(config)
@name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
#
#
...would result in ActiveRecord::Base.configurations to look like this:
database: db/production.sqlite3
adapter: sqlite3
production:
database: db/development.sqlite3
adapter: sqlite3
development:
For example, the following database.yml...
as an ActiveRecord::DatabaseConfigurations object.
Contains the database configuration - as is typically stored in config/database.yml -
#
def self.configurations=(config) @@configurations = ActiveRecord::DatabaseConfigurations.new(config) end
def self.connected_to_stack # :nodoc:
def self.connected_to_stack # :nodoc: if connected_to_stack = ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack] connected_to_stack else connected_to_stack = Concurrent::Array.new ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack] = connected_to_stack connected_to_stack end end
def self.connection_class # :nodoc:
def self.connection_class # :nodoc: @connection_class ||= false end
def self.connection_class=(b) # :nodoc:
def self.connection_class=(b) # :nodoc: @connection_class = b end
def self.connection_class? # :nodoc:
def self.connection_class? # :nodoc: self.connection_class end
def self.connection_class_for_self # :nodoc:
def self.connection_class_for_self # :nodoc: klass = self until klass == Base break if klass.connection_class? klass = klass.superclass end klass end
def self.connection_handler
def self.connection_handler ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] || default_connection_handler end
def self.connection_handler=(handler)
def self.connection_handler=(handler) ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler end
def self.connection_handlers
def self.connection_handlers if ActiveRecord.legacy_connection_handling else raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers." end @@connection_handlers ||= {} end
def self.connection_handlers=(handlers)
def self.connection_handlers=(handlers) if ActiveRecord.legacy_connection_handling ActiveSupport::Deprecation.warn(<<~MSG) Using legacy connection handling is deprecated. Please set `legacy_connection_handling` to `false` in your application. The new connection handling does not support `connection_handlers` getter and setter. Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling MSG else raise NotImplementedError, "The new connection handling does not support multiple connection handlers." end @@connection_handlers = handlers end
def self.current_preventing_writes
ActiveRecord::Base.current_preventing_writes #=> false
ActiveRecord::Base.connected_to(role: :writing) do
end
ActiveRecord::Base.current_preventing_writes #=> true
ActiveRecord::Base.connected_to(role: :reading) do
preventing writes.
Returns the symbol representing the current setting for
def self.current_preventing_writes if ActiveRecord.legacy_connection_handling connection_handler.prevent_writes else connected_to_stack.reverse_each do |hash| return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base) return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self) end false end end
def self.current_role
ActiveRecord::Base.current_role #=> :reading
ActiveRecord::Base.connected_to(role: :reading) do
end
ActiveRecord::Base.current_role #=> :writing
ActiveRecord::Base.connected_to(role: :writing) do
Returns the symbol representing the current connected role.
def self.current_role if ActiveRecord.legacy_connection_handling connection_handlers.key(connection_handler) || default_role else connected_to_stack.reverse_each do |hash| return hash[:role] if hash[:role] && hash[:klasses].include?(Base) return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self) end default_role end end
def self.current_shard
ActiveRecord::Base.current_shard #=> :one
ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
end
ActiveRecord::Base.current_shard #=> :default
ActiveRecord::Base.connected_to(role: :reading) do
Returns the symbol representing the current connected shard.
def self.current_shard connected_to_stack.reverse_each do |hash| return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base) return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_class_for_self) end default_shard end
def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
def self.strict_loading_violation!(owner:, reflection:) # :nodoc: case ActiveRecord.action_on_strict_loading_violation when :raise message = reflection.strict_loading_violation_message(owner) raise ActiveRecord::StrictLoadingViolationError.new(message) when :log name = "strict_loading_violation.active_record" ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection) end end
def <=>(other_object)
def <=>(other_object) if other_object.is_a?(self.class) to_key <=> other_object.to_key else super end end
def ==(comparison_object)
Note also that destroying a record preserves its ID in the model instance, so deleted
+select+ and leave the ID out, you're on your own, this predicate will return false.
other record is the receiver itself. Besides, if you fetch existing records with
Note that new records are different from any other record by definition, unless the
is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
Returns true if +comparison_object+ is the same exact object, or +comparison_object+
def ==(comparison_object) super || comparison_object.instance_of?(self.class) && !id.nil? && comparison_object.id == id end
def blank? # :nodoc:
def blank? # :nodoc: false end
def connection_handler
def connection_handler self.class.connection_handler end
def custom_inspect_method_defined?
def custom_inspect_method_defined? self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner end
def encode_with(coder)
Post.new.encode_with(coder)
coder = {}
end
class Post < ActiveRecord::Base
Example:
method.
guaranteed to match the structure of +coder+ passed to the #init_with
serialized. The structure of +coder+ defined in this method is
Populate +coder+ with attributes about this record that should be
def encode_with(coder) self.class.yaml_encoder.encode(@attributes, coder) coder["new_record"] = new_record? coder["active_record_yaml_version"] = 2 end
def freeze
accessible, even on destroyed records, but cloned models will not be
Clone and freeze the attributes hash such that associations are still
def freeze @attributes = @attributes.clone.freeze self end
def frozen?
def frozen? @attributes.frozen? end
def hash
Delegates to id in order to allow two records of the same type and id to work with something like:
def hash id = self.id if id self.class.hash ^ id.hash else super end end
def init_internals
def init_internals @readonly = false @previously_new_record = false @destroyed = false @marked_for_destruction = false @destroyed_by_association = nil @_start_transaction_state = nil klass = self.class @primary_key = klass.primary_key @strict_loading = klass.strict_loading_by_default @strict_loading_mode = :all klass.define_attribute_methods end
def init_with(coder, &block)
post.init_with(coder)
post = Post.allocate
old_post.encode_with(coder)
coder = {}
old_post = Post.new(title: "hello world")
end
class Post < ActiveRecord::Base
#encode_with.
the result of previously encoding an Active Record model, using
Initialize an empty model object from +coder+. +coder+ should be
def init_with(coder, &block) coder = LegacyYamlAdapter.convert(coder) attributes = self.class.yaml_encoder.decode(coder) init_with_attributes(attributes, coder["new_record"], &block) end
def init_with_attributes(attributes, new_record = false) # :nodoc:
`initialize` method, no assignment calls are made per attribute.
+attributes+ should be an attributes object, and unlike the
Initialize an empty model object from +attributes+.
#
def init_with_attributes(attributes, new_record = false) # :nodoc: @new_record = new_record @attributes = attributes init_internals yield self if block_given? _run_find_callbacks _run_initialize_callbacks self end
def initialize(attributes = nil)
# Instantiates a single new object
==== Example:
hence you can't have attributes that aren't part of the table columns.
In both instances, valid attribute keys are determined by the column names of the associated table --
attributes but not yet saved (pass a hash with key names matching the associated table column names).
New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
def initialize(attributes = nil) @new_record = true @attributes = self.class._default_attributes.deep_dup init_internals initialize_internals_callback assign_attributes(attributes) if attributes yield self if block_given? _run_initialize_callbacks end
def initialize_dup(other) # :nodoc:
#
def initialize_dup(other) # :nodoc: @attributes = @attributes.deep_dup @attributes.reset(@primary_key) _run_initialize_callbacks @new_record = true @previously_new_record = false @destroyed = false @_start_transaction_state = nil super end
def initialize_internals_callback
def initialize_internals_callback end
def inspect
def inspect # We check defined?(@attributes) not to issue warnings if the object is # allocated but not initialized. inspection = if defined?(@attributes) && @attributes self.class.attribute_names.filter_map do |name| if _has_attribute?(name) "#{name}: #{attribute_for_inspect(name)}" end end.join(", ") else "not initialized" end "#<#{self.class} #{inspection}>" end
def inspection_filter
def inspection_filter self.class.inspection_filter end
def present? # :nodoc:
def present? # :nodoc: true end
def pretty_print(pp)
Takes a PP and prettily prints this record to it, allowing you to get a nice result from pp record
def pretty_print(pp) return super if custom_inspect_method_defined? pp.object_address_group(self) do if defined?(@attributes) && @attributes attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) } pp.seplist(attr_names, proc { pp.text "," }) do |attr_name| pp.breakable " " pp.group(1) do pp.text attr_name pp.text ":" pp.breakable value = _read_attribute(attr_name) value = inspection_filter.filter_param(attr_name, value) unless value.nil? pp.pp value end end else pp.breakable " " pp.text "not initialized" end end end
def readonly!
def readonly! @readonly = true end
def readonly?
def readonly? @readonly end
def slice(*methods)
def slice(*methods) methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access end
def strict_loading!(value = true, mode: :all)
user.comments
user.strict_loading!(false) # => false
user = User.first
=== Example:
that will lead to an n plus one query is lazily loaded.
:n_plus_one_only mode will only raise an error if an association
* mode - Symbol specifying strict loading mode. Defaults to :all. Using
* value - Boolean specifying whether to enable or disable strict loading.
=== Parameters:
=> ActiveRecord::StrictLoadingViolationError
user.comments
user.strict_loading! # => true
user = User.first
if the record tries to lazily load an association.
Sets the record to strict_loading mode. This will raise an error
def strict_loading!(value = true, mode: :all) unless [:all, :n_plus_one_only].include?(mode) raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only]." end @strict_loading_mode = mode @strict_loading = value end
def strict_loading?
def strict_loading? @strict_loading end
def strict_loading_n_plus_one_only?
def strict_loading_n_plus_one_only? @strict_loading_mode == :n_plus_one_only end
def to_ary
So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here.
which significantly impacts upon performance.
+ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
the array, and then rescues from the possible +NoMethodError+. If those elements are
+Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
def to_ary nil end
def values_at(*methods)
def values_at(*methods) methods.flatten.map! { |method| public_send(method) } end