Support configuration on ActiveRecord::Model.
The problem: We need to be able to specify configuration in a way that can be inherited to models that include ActiveRecord::Model. So it is no longer sufficient to put 'top level' config on ActiveRecord::Base, but we do want configuration specified on ActiveRecord::Base and descendants to continue to work. So we need something like class_attribute that can be defined on a module but that is inherited when ActiveRecord::Model is included. The solution: added ActiveModel::Configuration module which provides a config_attribute macro. It's a bit specific hence I am not putting this in Active Support or making it a 'public API' at present.
This commit is contained in:
parent
afe6e059ea
commit
93c1f11c0a
|
@ -32,6 +32,7 @@ module ActiveModel
|
|||
autoload :AttributeMethods
|
||||
autoload :BlockValidator, 'active_model/validator'
|
||||
autoload :Callbacks
|
||||
autoload :Configuration
|
||||
autoload :Conversion
|
||||
autoload :Dirty
|
||||
autoload :EachValidator, 'active_model/validator'
|
||||
|
|
|
@ -61,7 +61,8 @@ module ActiveModel
|
|||
CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
|
||||
|
||||
included do
|
||||
class_attribute :attribute_method_matchers, :instance_writer => false
|
||||
extend ActiveModel::Configuration
|
||||
config_attribute :attribute_method_matchers
|
||||
self.attribute_method_matchers = [ClassMethods::AttributeMethodMatcher.new]
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
require 'active_support/concern'
|
||||
require 'active_support/core_ext/class/attribute'
|
||||
require 'active_support/core_ext/class/attribute_accessors'
|
||||
|
||||
module ActiveModel
|
||||
# This API is for Rails' internal use and is not currently considered 'public', so
|
||||
# it may change in the future without warning.
|
||||
#
|
||||
# It creates configuration attributes that can be inherited from a module down
|
||||
# to a class that includes the module. E.g.
|
||||
#
|
||||
# module MyModel
|
||||
# extend ActiveModel::Configuration
|
||||
# config_attribute :awesome
|
||||
# self.awesome = true
|
||||
# end
|
||||
#
|
||||
# class Post
|
||||
# include MyModel
|
||||
# end
|
||||
#
|
||||
# Post.awesome # => true
|
||||
#
|
||||
# Post.awesome = false
|
||||
# Post.awesome # => false
|
||||
# MyModel.awesome # => true
|
||||
#
|
||||
# We assume that the module will have a ClassMethods submodule containing methods
|
||||
# to be transferred to the including class' singleton class.
|
||||
#
|
||||
# Config options can also be defined directly on a class:
|
||||
#
|
||||
# class Post
|
||||
# extend ActiveModel::Configuration
|
||||
# config_attribute :awesome
|
||||
# end
|
||||
#
|
||||
# So this allows us to define a module that doesn't care about whether it is being
|
||||
# included in a class or a module:
|
||||
#
|
||||
# module Awesomeness
|
||||
# extend ActiveSupport::Concern
|
||||
#
|
||||
# included do
|
||||
# extend ActiveModel::Configuration
|
||||
# config_attribute :awesome
|
||||
# self.awesome = true
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# class Post
|
||||
# include Awesomeness
|
||||
# end
|
||||
#
|
||||
# module AwesomeModel
|
||||
# include Awesomeness
|
||||
# end
|
||||
module Configuration #:nodoc:
|
||||
def config_attribute(name, options = {})
|
||||
klass = self.is_a?(Class) ? ClassAttribute : ModuleAttribute
|
||||
klass.new(self, name, options).define
|
||||
end
|
||||
|
||||
class Attribute
|
||||
attr_reader :host, :name, :options
|
||||
|
||||
def initialize(host, name, options)
|
||||
@host, @name, @options = host, name, options
|
||||
end
|
||||
|
||||
def instance_writer?
|
||||
options.fetch(:instance_writer, false)
|
||||
end
|
||||
end
|
||||
|
||||
class ClassAttribute < Attribute
|
||||
def define
|
||||
if options[:global]
|
||||
host.cattr_accessor name, :instance_writer => instance_writer?
|
||||
else
|
||||
host.class_attribute name, :instance_writer => instance_writer?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ModuleAttribute < Attribute
|
||||
def class_methods
|
||||
@class_methods ||= begin
|
||||
if host.const_defined?(:ClassMethods, false)
|
||||
host.const_get(:ClassMethods)
|
||||
else
|
||||
host.const_set(:ClassMethods, Module.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def define
|
||||
host.singleton_class.class_eval <<-CODE, __FILE__, __LINE__
|
||||
attr_accessor :#{name}
|
||||
def #{name}?; !!#{name}; end
|
||||
CODE
|
||||
|
||||
name, host = self.name, self.host
|
||||
|
||||
class_methods.class_eval do
|
||||
define_method(name) { host.send(name) }
|
||||
define_method("#{name}?") { !!send(name) }
|
||||
end
|
||||
|
||||
host.class_eval <<-CODE
|
||||
def #{name}; defined?(@#{name}) ? @#{name} : self.class.#{name}; end
|
||||
def #{name}?; !!#{name}; end
|
||||
CODE
|
||||
|
||||
if options[:global]
|
||||
class_methods.class_eval do
|
||||
define_method("#{name}=") { |val| host.send("#{name}=", val) }
|
||||
end
|
||||
else
|
||||
class_methods.class_eval <<-CODE, __FILE__, __LINE__
|
||||
def #{name}=(val)
|
||||
singleton_class.class_eval do
|
||||
remove_possible_method(:#{name})
|
||||
define_method(:#{name}) { val }
|
||||
end
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
host.send(:attr_writer, name) if instance_writer?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,11 +10,13 @@ module ActiveModel
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_attribute :_accessible_attributes
|
||||
class_attribute :_protected_attributes
|
||||
class_attribute :_active_authorizer
|
||||
extend ActiveModel::Configuration
|
||||
|
||||
class_attribute :_mass_assignment_sanitizer
|
||||
config_attribute :_accessible_attributes
|
||||
config_attribute :_protected_attributes
|
||||
config_attribute :_active_authorizer
|
||||
|
||||
config_attribute :_mass_assignment_sanitizer
|
||||
self.mass_assignment_sanitizer = :logger
|
||||
end
|
||||
|
||||
|
@ -56,7 +58,7 @@ module ActiveModel
|
|||
# You can specify your own sanitizer object eg. MySanitizer.new.
|
||||
# See <tt>ActiveModel::MassAssignmentSecurity::LoggerSanitizer</tt> for example implementation.
|
||||
#
|
||||
#
|
||||
#
|
||||
module ClassMethods
|
||||
# Attributes named in this macro are protected from mass-assignment
|
||||
# whenever attributes are sanitized before assignment. A role for the
|
||||
|
@ -70,13 +72,13 @@ module ActiveModel
|
|||
#
|
||||
# class Customer
|
||||
# include ActiveModel::MassAssignmentSecurity
|
||||
#
|
||||
#
|
||||
# attr_accessor :name, :email, :logins_count
|
||||
#
|
||||
#
|
||||
# attr_protected :logins_count
|
||||
# # Suppose that admin can not change email for customer
|
||||
# attr_protected :logins_count, :email, :as => :admin
|
||||
#
|
||||
# attr_protected :logins_count, :email, :as => :admin
|
||||
#
|
||||
# def assign_attributes(values, options = {})
|
||||
# sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
||||
# send("#{k}=", v)
|
||||
|
@ -99,7 +101,7 @@ module ActiveModel
|
|||
# customer.name # => "David"
|
||||
# customer.email # => nil
|
||||
# customer.logins_count # => nil
|
||||
#
|
||||
#
|
||||
# customer.email = "c@d.com"
|
||||
# customer.email # => "c@d.com"
|
||||
#
|
||||
|
|
|
@ -10,8 +10,9 @@ module ActiveModel
|
|||
|
||||
included do
|
||||
extend ActiveModel::Naming
|
||||
extend ActiveModel::Configuration
|
||||
|
||||
class_attribute :include_root_in_json
|
||||
config_attribute :include_root_in_json
|
||||
self.include_root_in_json = true
|
||||
end
|
||||
|
||||
|
|
|
@ -42,9 +42,9 @@ module ActiveModel
|
|||
#
|
||||
module Validations
|
||||
extend ActiveSupport::Concern
|
||||
include ActiveSupport::Callbacks
|
||||
|
||||
included do
|
||||
extend ActiveModel::Callbacks
|
||||
extend ActiveModel::Translation
|
||||
|
||||
extend HelperMethods
|
||||
|
@ -53,7 +53,8 @@ module ActiveModel
|
|||
attr_accessor :validation_context
|
||||
define_callbacks :validate, :scope => :name
|
||||
|
||||
class_attribute :_validators
|
||||
extend ActiveModel::Configuration
|
||||
config_attribute :_validators
|
||||
self._validators = Hash.new { |h,k| h[k] = [] }
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
require 'cases/helper'
|
||||
|
||||
class ConfigurationOnModuleTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@mod = mod = Module.new do
|
||||
extend ActiveSupport::Concern
|
||||
extend ActiveModel::Configuration
|
||||
|
||||
config_attribute :omg
|
||||
self.omg = "default"
|
||||
|
||||
config_attribute :wtf, global: true
|
||||
self.wtf = "default"
|
||||
|
||||
config_attribute :boolean
|
||||
|
||||
config_attribute :lol, instance_writer: true
|
||||
end
|
||||
|
||||
@klass = Class.new do
|
||||
include mod
|
||||
end
|
||||
|
||||
@subklass = Class.new(@klass)
|
||||
end
|
||||
|
||||
test "default" do
|
||||
assert_equal "default", @mod.omg
|
||||
assert_equal "default", @klass.omg
|
||||
assert_equal "default", @klass.new.omg
|
||||
end
|
||||
|
||||
test "setting" do
|
||||
@mod.omg = "lol"
|
||||
assert_equal "lol", @mod.omg
|
||||
end
|
||||
|
||||
test "setting on class including the module" do
|
||||
@klass.omg = "lol"
|
||||
assert_equal "lol", @klass.omg
|
||||
assert_equal "lol", @klass.new.omg
|
||||
assert_equal "default", @mod.omg
|
||||
end
|
||||
|
||||
test "setting on subclass of class including the module" do
|
||||
@subklass.omg = "lol"
|
||||
assert_equal "lol", @subklass.omg
|
||||
assert_equal "default", @klass.omg
|
||||
assert_equal "default", @mod.omg
|
||||
end
|
||||
|
||||
test "setting on instance" do
|
||||
assert !@klass.new.respond_to?(:omg=)
|
||||
|
||||
@klass.lol = "lol"
|
||||
obj = @klass.new
|
||||
assert_equal "lol", obj.lol
|
||||
obj.lol = "omg"
|
||||
assert_equal "omg", obj.lol
|
||||
assert_equal "lol", @klass.lol
|
||||
assert_equal "lol", @klass.new.lol
|
||||
obj.lol = false
|
||||
assert !obj.lol?
|
||||
end
|
||||
|
||||
test "global attribute" do
|
||||
assert_equal "default", @mod.wtf
|
||||
assert_equal "default", @klass.wtf
|
||||
|
||||
@mod.wtf = "wtf"
|
||||
|
||||
assert_equal "wtf", @mod.wtf
|
||||
assert_equal "wtf", @klass.wtf
|
||||
|
||||
@klass.wtf = "lol"
|
||||
|
||||
assert_equal "lol", @mod.wtf
|
||||
assert_equal "lol", @klass.wtf
|
||||
end
|
||||
|
||||
test "boolean" do
|
||||
assert_equal false, @mod.boolean?
|
||||
assert_equal false, @klass.new.boolean?
|
||||
@mod.boolean = true
|
||||
assert_equal true, @mod.boolean?
|
||||
assert_equal true, @klass.new.boolean?
|
||||
end
|
||||
end
|
||||
|
||||
class ConfigurationOnClassTest < ActiveModel::TestCase
|
||||
def setup
|
||||
@klass = Class.new do
|
||||
extend ActiveModel::Configuration
|
||||
|
||||
config_attribute :omg
|
||||
self.omg = "default"
|
||||
|
||||
config_attribute :wtf, global: true
|
||||
self.wtf = "default"
|
||||
|
||||
config_attribute :omg2, instance_writer: true
|
||||
config_attribute :wtf2, instance_writer: true, global: true
|
||||
end
|
||||
|
||||
@subklass = Class.new(@klass)
|
||||
end
|
||||
|
||||
test "defaults" do
|
||||
assert_equal "default", @klass.omg
|
||||
assert_equal "default", @klass.wtf
|
||||
assert_equal "default", @subklass.omg
|
||||
assert_equal "default", @subklass.wtf
|
||||
end
|
||||
|
||||
test "changing" do
|
||||
@klass.omg = "lol"
|
||||
assert_equal "lol", @klass.omg
|
||||
assert_equal "lol", @subklass.omg
|
||||
end
|
||||
|
||||
test "changing in subclass" do
|
||||
@subklass.omg = "lol"
|
||||
assert_equal "lol", @subklass.omg
|
||||
assert_equal "default", @klass.omg
|
||||
end
|
||||
|
||||
test "changing global" do
|
||||
@klass.wtf = "wtf"
|
||||
assert_equal "wtf", @klass.wtf
|
||||
assert_equal "wtf", @subklass.wtf
|
||||
|
||||
@subklass.wtf = "lol"
|
||||
assert_equal "lol", @klass.wtf
|
||||
assert_equal "lol", @subklass.wtf
|
||||
end
|
||||
|
||||
test "instance_writer" do
|
||||
obj = @klass.new
|
||||
|
||||
@klass.omg2 = "omg"
|
||||
@klass.wtf2 = "wtf"
|
||||
|
||||
assert_equal "omg", obj.omg2
|
||||
assert_equal "wtf", obj.wtf2
|
||||
|
||||
obj.omg2 = "lol"
|
||||
obj.wtf2 = "lol"
|
||||
|
||||
assert_equal "lol", obj.omg2
|
||||
assert_equal "lol", obj.wtf2
|
||||
assert_equal "omg", @klass.omg2
|
||||
assert_equal "lol", @klass.wtf2
|
||||
end
|
||||
end
|
|
@ -57,7 +57,6 @@ module ActiveRecord
|
|||
|
||||
autoload :Base
|
||||
autoload :Callbacks
|
||||
autoload :Configuration
|
||||
autoload :Core
|
||||
autoload :CounterCache
|
||||
autoload :DynamicMatchers
|
||||
|
|
|
@ -13,7 +13,7 @@ module ActiveRecord
|
|||
raise "You cannot include Dirty after Timestamp"
|
||||
end
|
||||
|
||||
class_attribute :partial_updates
|
||||
config_attribute :partial_updates
|
||||
self.partial_updates = true
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,10 @@ module ActiveRecord
|
|||
|
||||
ATTRIBUTE_TYPES_CACHED_BY_DEFAULT = [:datetime, :timestamp, :time, :date]
|
||||
|
||||
Configuration.define :attribute_types_cached_by_default, ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
|
||||
included do
|
||||
config_attribute :attribute_types_cached_by_default, :global => true
|
||||
self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# +cache_attributes+ allows you to declare which converted attribute values should
|
||||
|
|
|
@ -6,7 +6,7 @@ module ActiveRecord
|
|||
included do
|
||||
# Returns a hash of all the attributes that have been specified for serialization as
|
||||
# keys and their class restriction as values.
|
||||
class_attribute :serialized_attributes
|
||||
config_attribute :serialized_attributes
|
||||
self.serialized_attributes = {}
|
||||
end
|
||||
|
||||
|
|
|
@ -6,10 +6,11 @@ module ActiveRecord
|
|||
module TimeZoneConversion
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
Configuration.define :time_zone_aware_attributes, false
|
||||
|
||||
included do
|
||||
class_attribute :skip_time_zone_conversion_for_attributes, :instance_writer => false
|
||||
config_attribute :time_zone_aware_attributes, :global => true
|
||||
self.time_zone_aware_attributes = false
|
||||
|
||||
config_attribute :skip_time_zone_conversion_for_attributes
|
||||
self.skip_time_zone_conversion_for_attributes = []
|
||||
end
|
||||
|
||||
|
|
|
@ -328,7 +328,6 @@ module ActiveRecord #:nodoc:
|
|||
# instances in the current object space.
|
||||
class Base
|
||||
include ActiveRecord::Model
|
||||
self.connection_handler = ConnectionAdapters::ConnectionHandler.new
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ module ActiveRecord
|
|||
# Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
|
||||
# <tt>after_rollback</tt>.
|
||||
#
|
||||
# Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
|
||||
# Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
|
||||
# is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
|
||||
# are instantiated as well.
|
||||
#
|
||||
|
@ -215,24 +215,48 @@ module ActiveRecord
|
|||
# instead of quietly returning +false+.
|
||||
#
|
||||
# == Debugging callbacks
|
||||
#
|
||||
# The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. ActiveModel Callbacks support
|
||||
#
|
||||
# The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. ActiveModel Callbacks support
|
||||
# <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
|
||||
# defines what part of the chain the callback runs in.
|
||||
#
|
||||
# To find all callbacks in the before_save callback chain:
|
||||
#
|
||||
#
|
||||
# To find all callbacks in the before_save callback chain:
|
||||
#
|
||||
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
|
||||
#
|
||||
#
|
||||
# Returns an array of callback objects that form the before_save chain.
|
||||
#
|
||||
#
|
||||
# To further check if the before_save chain contains a proc defined as <tt>rest_when_dead</tt> use the <tt>filter</tt> property of the callback object:
|
||||
#
|
||||
#
|
||||
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead)
|
||||
#
|
||||
#
|
||||
# Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model.
|
||||
#
|
||||
#
|
||||
module Callbacks
|
||||
# We can't define callbacks directly on ActiveRecord::Model because
|
||||
# it is a module. So we queue up the definitions and execute them
|
||||
# when ActiveRecord::Model is included.
|
||||
module Register #:nodoc:
|
||||
def self.extended(base)
|
||||
base.config_attribute :_callbacks_register
|
||||
base._callbacks_register = []
|
||||
end
|
||||
|
||||
def self.setup(base)
|
||||
base._callbacks_register.each do |item|
|
||||
base.send(*item)
|
||||
end
|
||||
end
|
||||
|
||||
def define_callbacks(*args)
|
||||
self._callbacks_register << [:define_callbacks, *args]
|
||||
end
|
||||
|
||||
def define_model_callbacks(*args)
|
||||
self._callbacks_register << [:define_model_callbacks, *args]
|
||||
end
|
||||
end
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
CALLBACKS = [
|
||||
|
@ -242,8 +266,11 @@ module ActiveRecord
|
|||
:before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
|
||||
]
|
||||
|
||||
module ClassMethods
|
||||
include ActiveModel::Callbacks
|
||||
end
|
||||
|
||||
included do
|
||||
extend ActiveModel::Callbacks
|
||||
include ActiveModel::Validations::Callbacks
|
||||
|
||||
define_model_callbacks :initialize, :find, :touch, :only => :after
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
require 'active_support/concern'
|
||||
|
||||
module ActiveRecord
|
||||
# This module allows configuration options to be specified in a way such that
|
||||
# ActiveRecord::Base and ActiveRecord::Model will have access to the same value,
|
||||
# and will automatically get the appropriate readers and writers defined.
|
||||
#
|
||||
# In the future, we should probably move away from defining global config
|
||||
# directly on ActiveRecord::Base / ActiveRecord::Model.
|
||||
module Configuration #:nodoc:
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
end
|
||||
|
||||
def self.define(name, default = nil)
|
||||
singleton_class.send(:attr_accessor, name)
|
||||
|
||||
[self, ClassMethods].each do |klass|
|
||||
klass.class_eval <<-CODE, __FILE__, __LINE__
|
||||
def #{name}
|
||||
ActiveRecord::Configuration.#{name}
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
ClassMethods.class_eval <<-CODE, __FILE__, __LINE__
|
||||
def #{name}=(val)
|
||||
ActiveRecord::Configuration.#{name} = val
|
||||
end
|
||||
CODE
|
||||
|
||||
send("#{name}=", default) unless default.nil?
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,70 +4,75 @@ module ActiveRecord
|
|||
module Core
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class,
|
||||
# which is then passed on to any new database connections made and which can be retrieved on both
|
||||
# a class and instance level by calling +logger+.
|
||||
Configuration.define :logger
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Contains the database configuration - as is typically stored in config/database.yml -
|
||||
# as a Hash.
|
||||
#
|
||||
# For example, the following database.yml...
|
||||
#
|
||||
# development:
|
||||
# adapter: sqlite3
|
||||
# database: db/development.sqlite3
|
||||
#
|
||||
# production:
|
||||
# adapter: sqlite3
|
||||
# database: db/production.sqlite3
|
||||
#
|
||||
# ...would result in ActiveRecord::Base.configurations to look like this:
|
||||
#
|
||||
# {
|
||||
# 'development' => {
|
||||
# 'adapter' => 'sqlite3',
|
||||
# 'database' => 'db/development.sqlite3'
|
||||
# },
|
||||
# 'production' => {
|
||||
# 'adapter' => 'sqlite3',
|
||||
# 'database' => 'db/production.sqlite3'
|
||||
# }
|
||||
# }
|
||||
Configuration.define :configurations, {}
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
|
||||
# dates and times from the database. This is set to :local by default.
|
||||
Configuration.define :default_timezone, :local
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Specifies the format to use when dumping the database schema with Rails'
|
||||
# Rakefile. If :sql, the schema is dumped as (potentially database-
|
||||
# specific) SQL statements. If :ruby, the schema is dumped as an
|
||||
# ActiveRecord::Schema file which can be loaded into any database that
|
||||
# supports migrations. Use :ruby if you want to have different database
|
||||
# adapters for, e.g., your development and test environments.
|
||||
Configuration.define :schema_format, :ruby
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Specify whether or not to use timestamps for migration versions
|
||||
Configuration.define :timestamped_migrations, true
|
||||
|
||||
included do
|
||||
##
|
||||
# :singleton-method:
|
||||
# The connection handler
|
||||
class_attribute :connection_handler, :instance_writer => false
|
||||
# Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class,
|
||||
# which is then passed on to any new database connections made and which can be retrieved on both
|
||||
# a class and instance level by calling +logger+.
|
||||
config_attribute :logger, :global => true
|
||||
|
||||
initialize_generated_modules unless self == Base
|
||||
##
|
||||
# :singleton-method:
|
||||
# Contains the database configuration - as is typically stored in config/database.yml -
|
||||
# as a Hash.
|
||||
#
|
||||
# For example, the following database.yml...
|
||||
#
|
||||
# development:
|
||||
# adapter: sqlite3
|
||||
# database: db/development.sqlite3
|
||||
#
|
||||
# production:
|
||||
# adapter: sqlite3
|
||||
# database: db/production.sqlite3
|
||||
#
|
||||
# ...would result in ActiveRecord::Base.configurations to look like this:
|
||||
#
|
||||
# {
|
||||
# 'development' => {
|
||||
# 'adapter' => 'sqlite3',
|
||||
# 'database' => 'db/development.sqlite3'
|
||||
# },
|
||||
# 'production' => {
|
||||
# 'adapter' => 'sqlite3',
|
||||
# 'database' => 'db/production.sqlite3'
|
||||
# }
|
||||
# }
|
||||
config_attribute :configurations, :global => true
|
||||
self.configurations = {}
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
|
||||
# dates and times from the database. This is set to :local by default.
|
||||
config_attribute :default_timezone, :global => true
|
||||
self.default_timezone = :local
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Specifies the format to use when dumping the database schema with Rails'
|
||||
# Rakefile. If :sql, the schema is dumped as (potentially database-
|
||||
# specific) SQL statements. If :ruby, the schema is dumped as an
|
||||
# ActiveRecord::Schema file which can be loaded into any database that
|
||||
# supports migrations. Use :ruby if you want to have different database
|
||||
# adapters for, e.g., your development and test environments.
|
||||
config_attribute :schema_format, :global => true
|
||||
self.schema_format = :ruby
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Specify whether or not to use timestamps for migration versions
|
||||
config_attribute :timestamped_migrations, :global => true
|
||||
self.timestamped_migrations = true
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# The connection handler
|
||||
config_attribute :connection_handler
|
||||
self.connection_handler = ConnectionAdapters::ConnectionHandler.new
|
||||
|
||||
#
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
|
|
@ -2,9 +2,11 @@ require 'active_support/core_ext/class/attribute'
|
|||
|
||||
module ActiveRecord
|
||||
module Explain
|
||||
# If a query takes longer than these many seconds we log its query plan
|
||||
# automatically. nil disables this feature.
|
||||
Configuration.define :auto_explain_threshold_in_seconds
|
||||
def self.extended(base)
|
||||
# If a query takes longer than these many seconds we log its query plan
|
||||
# automatically. nil disables this feature.
|
||||
base.config_attribute :auto_explain_threshold_in_seconds, :global => true
|
||||
end
|
||||
|
||||
# If auto explain is enabled, this method triggers EXPLAIN logging for the
|
||||
# queries triggered by the block if it takes more than the threshold as a
|
||||
|
|
|
@ -6,7 +6,7 @@ module ActiveRecord
|
|||
|
||||
included do
|
||||
# Determine whether to store the full constant name including namespace when using STI
|
||||
class_attribute :store_full_sti_class
|
||||
config_attribute :store_full_sti_class
|
||||
self.store_full_sti_class = true
|
||||
end
|
||||
|
||||
|
@ -88,7 +88,7 @@ module ActiveRecord
|
|||
#
|
||||
# Mainly for internal use.
|
||||
def active_record_super #:nodoc:
|
||||
if self == Base || superclass && superclass < Model::Tag
|
||||
if self == Base || superclass && superclass < Model
|
||||
superclass
|
||||
else
|
||||
Base
|
||||
|
@ -100,7 +100,7 @@ module ActiveRecord
|
|||
# Returns the class descending directly from ActiveRecord::Base or an
|
||||
# abstract class, if any, in the inheritance hierarchy.
|
||||
def class_of_active_record_descendant(klass)
|
||||
unless klass < Model::Tag
|
||||
unless klass < Model
|
||||
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
|
||||
end
|
||||
|
||||
|
|
|
@ -48,7 +48,10 @@ module ActiveRecord
|
|||
module Optimistic
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
Configuration.define :lock_optimistically, true
|
||||
included do
|
||||
config_attribute :lock_optimistically, :global => true
|
||||
self.lock_optimistically = true
|
||||
end
|
||||
|
||||
def locking_enabled? #:nodoc:
|
||||
self.class.locking_enabled?
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'active_support/deprecation'
|
||||
require 'active_support/concern'
|
||||
|
||||
module ActiveRecord
|
||||
# <tt>ActiveRecord::Model</tt> can be included into a class to add Active Record persistence.
|
||||
|
@ -9,57 +10,61 @@ module ActiveRecord
|
|||
# end
|
||||
#
|
||||
module Model
|
||||
# So we can recognise an AR class even while self.included is being
|
||||
# executed. (At that time, klass < Model == false.)
|
||||
module Tag #:nodoc:
|
||||
module ClassMethods #:nodoc:
|
||||
include ActiveSupport::Callbacks::ClassMethods
|
||||
include ActiveModel::Naming
|
||||
include QueryCache::ClassMethods
|
||||
include ActiveSupport::Benchmarkable
|
||||
include ActiveSupport::DescendantsTracker
|
||||
|
||||
include Querying
|
||||
include Translation
|
||||
include DynamicMatchers
|
||||
include CounterCache
|
||||
include Explain
|
||||
end
|
||||
|
||||
def self.included(base)
|
||||
return if base < Tag
|
||||
return if base.singleton_class < ClassMethods
|
||||
|
||||
base.class_eval do
|
||||
include Tag
|
||||
|
||||
include Configuration
|
||||
|
||||
include ActiveRecord::Persistence
|
||||
extend ActiveModel::Naming
|
||||
extend QueryCache::ClassMethods
|
||||
extend ActiveSupport::Benchmarkable
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
|
||||
extend Querying
|
||||
include ReadonlyAttributes
|
||||
include ModelSchema
|
||||
extend Translation
|
||||
include Inheritance
|
||||
include Scoping
|
||||
extend DynamicMatchers
|
||||
include Sanitization
|
||||
include Integration
|
||||
include AttributeAssignment
|
||||
include ActiveModel::Conversion
|
||||
include Validations
|
||||
extend CounterCache
|
||||
include Locking::Optimistic, Locking::Pessimistic
|
||||
include AttributeMethods
|
||||
include Callbacks, ActiveModel::Observing, Timestamp
|
||||
include Associations
|
||||
include IdentityMap
|
||||
include ActiveModel::SecurePassword
|
||||
extend Explain
|
||||
|
||||
# AutosaveAssociation needs to be included before Transactions, because we want
|
||||
# #save_with_autosave_associations to be wrapped inside a transaction.
|
||||
include AutosaveAssociation, NestedAttributes
|
||||
include Aggregations, Transactions, Reflection, Serialization, Store
|
||||
|
||||
include Core
|
||||
|
||||
self.connection_handler = Base.connection_handler
|
||||
extend ClassMethods
|
||||
Callbacks::Register.setup(self)
|
||||
initialize_generated_modules unless self == Base
|
||||
end
|
||||
end
|
||||
|
||||
extend ActiveModel::Configuration
|
||||
extend ActiveModel::Callbacks
|
||||
extend ActiveModel::MassAssignmentSecurity::ClassMethods
|
||||
extend ActiveModel::AttributeMethods::ClassMethods
|
||||
extend Callbacks::Register
|
||||
extend Explain
|
||||
|
||||
def self.extend(*modules)
|
||||
ClassMethods.send(:include, *modules)
|
||||
end
|
||||
|
||||
include Persistence
|
||||
include ReadonlyAttributes
|
||||
include ModelSchema
|
||||
include Inheritance
|
||||
include Scoping
|
||||
include Sanitization
|
||||
include Integration
|
||||
include AttributeAssignment
|
||||
include ActiveModel::Conversion
|
||||
include Validations
|
||||
include Locking::Optimistic, Locking::Pessimistic
|
||||
include AttributeMethods
|
||||
include Callbacks, ActiveModel::Observing, Timestamp
|
||||
include Associations
|
||||
include IdentityMap
|
||||
include ActiveModel::SecurePassword
|
||||
include AutosaveAssociation, NestedAttributes
|
||||
include Aggregations, Transactions, Reflection, Serialization, Store
|
||||
include Core
|
||||
|
||||
module DeprecationProxy #:nodoc:
|
||||
class << self
|
||||
instance_methods.each { |m| undef_method m unless m =~ /^__|^object_id$|^instance_eval$/ }
|
||||
|
|
|
@ -5,16 +5,16 @@ module ActiveRecord
|
|||
module ModelSchema
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Accessor for the prefix type that will be prepended to every primary key column name.
|
||||
# The options are :table_name and :table_name_with_underscore. If the first is specified,
|
||||
# the Product class will look for "productid" instead of "id" as the primary column. If the
|
||||
# latter is specified, the Product class will look for "product_id" instead of "id". Remember
|
||||
# that this is a global setting for all Active Records.
|
||||
Configuration.define :primary_key_prefix_type
|
||||
|
||||
included do
|
||||
##
|
||||
# :singleton-method:
|
||||
# Accessor for the prefix type that will be prepended to every primary key column name.
|
||||
# The options are :table_name and :table_name_with_underscore. If the first is specified,
|
||||
# the Product class will look for "productid" instead of "id" as the primary column. If the
|
||||
# latter is specified, the Product class will look for "product_id" instead of "id". Remember
|
||||
# that this is a global setting for all Active Records.
|
||||
config_attribute :primary_key_prefix_type, :global => true
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Accessor for the name of the prefix string to prepend to every table name. So if set
|
||||
|
@ -25,14 +25,14 @@ module ActiveRecord
|
|||
# If you are organising your models within modules you can add a prefix to the models within
|
||||
# a namespace by defining a singleton method in the parent module called table_name_prefix which
|
||||
# returns your chosen prefix.
|
||||
class_attribute :table_name_prefix, :instance_writer => false
|
||||
config_attribute :table_name_prefix
|
||||
self.table_name_prefix = ""
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
|
||||
# "people_basecamp"). By default, the suffix is the empty string.
|
||||
class_attribute :table_name_suffix, :instance_writer => false
|
||||
config_attribute :table_name_suffix
|
||||
self.table_name_suffix = ""
|
||||
|
||||
##
|
||||
|
@ -40,7 +40,7 @@ module ActiveRecord
|
|||
# Indicates whether table names should be the pluralized versions of the corresponding class names.
|
||||
# If true, the default table name for a Product class will be +products+. If false, it would just be +product+.
|
||||
# See table_name for the full rules on table/class naming. This is true, by default.
|
||||
class_attribute :pluralize_table_names, :instance_writer => false
|
||||
config_attribute :pluralize_table_names
|
||||
self.pluralize_table_names = true
|
||||
end
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ module ActiveRecord
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_attribute :nested_attributes_options, :instance_writer => false
|
||||
config_attribute :nested_attributes_options
|
||||
self.nested_attributes_options = {}
|
||||
end
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ module ActiveRecord
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_attribute :_attr_readonly, :instance_writer => false
|
||||
config_attribute :_attr_readonly
|
||||
self._attr_readonly = []
|
||||
end
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ module ActiveRecord
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_attribute :reflections
|
||||
extend ActiveModel::Configuration
|
||||
config_attribute :reflections
|
||||
self.reflections = {}
|
||||
end
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ module ActiveRecord
|
|||
|
||||
included do
|
||||
# Stores the default scope for the class
|
||||
class_attribute :default_scopes, :instance_writer => false
|
||||
config_attribute :default_scopes
|
||||
self.default_scopes = []
|
||||
end
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ module ActiveRecord
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_attribute :record_timestamps
|
||||
config_attribute :record_timestamps, :instance_writer => true
|
||||
self.record_timestamps = true
|
||||
end
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ module ActiveRecord
|
|||
def self.active_record_super; Base; end
|
||||
def self.base_class; self; end
|
||||
|
||||
include ActiveRecord::Configuration
|
||||
include ActiveRecord::AttributeMethods
|
||||
|
||||
def self.column_names
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
require 'cases/helper'
|
||||
|
||||
class ConfigurationTest < ActiveRecord::TestCase
|
||||
def test_configuration
|
||||
@klass = Class.new do
|
||||
include ActiveRecord::Configuration
|
||||
end
|
||||
|
||||
ActiveRecord::Configuration.define :omg
|
||||
|
||||
ActiveRecord::Configuration.omg = "omg"
|
||||
|
||||
assert_equal "omg", @klass.new.omg
|
||||
assert !@klass.new.respond_to?(:omg=)
|
||||
assert_equal "omg", @klass.omg
|
||||
|
||||
@klass.omg = "wtf"
|
||||
|
||||
assert_equal "wtf", @klass.omg
|
||||
assert_equal "wtf", @klass.new.omg
|
||||
ensure
|
||||
ActiveRecord::Configuration.send(:undef_method, :omg)
|
||||
ActiveRecord::Configuration::ClassMethods.send(:undef_method, :omg)
|
||||
ActiveRecord::Configuration::ClassMethods.send(:undef_method, :omg=)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue