Rails 2.1
Update to Rails 2.1 final.
This commit is contained in:
parent
fd554cce90
commit
516d6dfac0
257 changed files with 4058 additions and 1933 deletions
|
@ -92,19 +92,19 @@ module ActiveRecord
|
|||
#
|
||||
# == Writing value objects
|
||||
#
|
||||
# Value objects are immutable and interchangeable objects that represent a given value, such as a +Money+ object representing
|
||||
# $5. Two +Money+ objects both representing $5 should be equal (through methods such as == and <=> from +Comparable+ if ranking
|
||||
# makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as +Customer+ can
|
||||
# Value objects are immutable and interchangeable objects that represent a given value, such as a Money object representing
|
||||
# $5. Two Money objects both representing $5 should be equal (through methods such as <tt>==</tt> and <tt><=></tt> from Comparable if ranking
|
||||
# makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as Customer can
|
||||
# easily have two different objects that both have an address on Hyancintvej. Entity identity is determined by object or
|
||||
# relational unique identifiers (such as primary keys). Normal <tt>ActiveRecord::Base</tt> classes are entity objects.
|
||||
# relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects.
|
||||
#
|
||||
# It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after
|
||||
# creation. Create a new +Money+ object with the new value instead. This is exemplified by the <tt>Money#exchanged_to</tt> method that
|
||||
# It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after
|
||||
# creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that
|
||||
# returns a new value object instead of changing its own values. Active Record won't persist value objects that have been
|
||||
# changed through means other than the writer method.
|
||||
#
|
||||
# The immutable requirement is enforced by Active Record by freezing any object assigned as a value object. Attempting to
|
||||
# change it afterwards will result in a <tt>ActiveSupport::FrozenObjectError</tt>.
|
||||
# change it afterwards will result in a ActiveSupport::FrozenObjectError.
|
||||
#
|
||||
# Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects
|
||||
# immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
|
||||
|
@ -123,8 +123,8 @@ module ActiveRecord
|
|||
#
|
||||
# Options are:
|
||||
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
||||
# from the part id. So <tt>composed_of :address</tt> will by default be linked to the +Address+ class, but
|
||||
# if the real class name is +CompanyAddress+, you'll have to specify it with this option.
|
||||
# from the part id. So <tt>composed_of :address</tt> will by default be linked to the Address class, but
|
||||
# if the real class name is CompanyAddress, you'll have to specify it with this option.
|
||||
# * <tt>:mapping</tt> - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name
|
||||
# to a constructor parameter on the value class.
|
||||
# * <tt>:allow_nil</tt> - specifies that the aggregate object will not be instantiated when all mapped
|
||||
|
|
173
vendor/rails/activerecord/lib/active_record/associations.rb
vendored
Normal file → Executable file
173
vendor/rails/activerecord/lib/active_record/associations.rb
vendored
Normal file → Executable file
|
@ -155,7 +155,7 @@ module ActiveRecord
|
|||
#
|
||||
# == Cardinality and associations
|
||||
#
|
||||
# ActiveRecord associations can be used to describe one-to-one, one-to-many and many-to-many
|
||||
# Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
|
||||
# relationships between models. Each model uses an association to describe its role in
|
||||
# the relation. The +belongs_to+ association is always used in the model that has
|
||||
# the foreign key.
|
||||
|
@ -441,9 +441,9 @@ module ActiveRecord
|
|||
#
|
||||
# == Eager loading of associations
|
||||
#
|
||||
# Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is
|
||||
# Eager loading is a way to find objects of a certain class and a number of named associations. This is
|
||||
# one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author
|
||||
# triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example:
|
||||
# triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 2. Example:
|
||||
#
|
||||
# class Post < ActiveRecord::Base
|
||||
# belongs_to :author
|
||||
|
@ -452,7 +452,7 @@ module ActiveRecord
|
|||
#
|
||||
# Consider the following loop using the class above:
|
||||
#
|
||||
# for post in Post.find(:all)
|
||||
# for post in Post.all
|
||||
# puts "Post: " + post.title
|
||||
# puts "Written by: " + post.author.name
|
||||
# puts "Last comment on: " + post.comments.first.created_on
|
||||
|
@ -462,14 +462,15 @@ module ActiveRecord
|
|||
#
|
||||
# for post in Post.find(:all, :include => :author)
|
||||
#
|
||||
# This references the name of the +belongs_to+ association that also used the <tt>:author</tt> symbol, so the find will now weave in a join something
|
||||
# like this: <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Doing so will cut down the number of queries from 201 to 101.
|
||||
# This references the name of the +belongs_to+ association that also used the <tt>:author</tt> symbol. After loading the posts, find
|
||||
# will collect the +author_id+ from each one and load all the referenced authors with one query. Doing so will cut down the number of queries from 201 to 102.
|
||||
#
|
||||
# We can improve upon the situation further by referencing both associations in the finder with:
|
||||
#
|
||||
# for post in Post.find(:all, :include => [ :author, :comments ])
|
||||
#
|
||||
# That'll add another join along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt>. And we'll be down to 1 query.
|
||||
# This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries
|
||||
# will be 1 plus the number of associations named (except if some of the associations are polymorphic +belongs_to+ - see below).
|
||||
#
|
||||
# To include a deep hierarchy of associations, use a hash:
|
||||
#
|
||||
|
@ -482,81 +483,91 @@ module ActiveRecord
|
|||
# the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no
|
||||
# catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above.
|
||||
#
|
||||
# Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So
|
||||
# <tt>:order => "posts.id DESC"</tt> will work while <tt>:order => "id DESC"</tt> will not. Because eager loading generates the +SELECT+ statement too, the
|
||||
# <tt>:select</tt> option is ignored.
|
||||
# Since only one table is loaded at a time, conditions or orders cannot reference tables other than the main one. If this is the case
|
||||
# Active Record falls back to the previously used LEFT OUTER JOIN based strategy. For example
|
||||
#
|
||||
# Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true])
|
||||
#
|
||||
# You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions
|
||||
# as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich
|
||||
# associations" with +has_and_belongs_to_many+ are not a good fit for eager loading.
|
||||
# will result in a single SQL query with joins along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
|
||||
# <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions like this can have unintended consequences.
|
||||
# In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole
|
||||
# and not just to the association. You must disambiguate column references for this fallback to happen, for example
|
||||
# <tt>:order => "author.name DESC"</tt> will work but <tt>:order => "name DESC"</tt> will not.
|
||||
#
|
||||
# If you do want eagerload only some members of an association it is usually more natural to <tt>:include</tt> an association
|
||||
# which has conditions defined on it:
|
||||
#
|
||||
# class Post < ActiveRecord::Base
|
||||
# has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true]
|
||||
# end
|
||||
#
|
||||
# Post.find(:all, :include => :approved_comments)
|
||||
#
|
||||
# will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved.
|
||||
#
|
||||
# When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated
|
||||
# before the actual model exists.
|
||||
#
|
||||
# Eager loading is not supported with polymorphic associations up to (and including)
|
||||
# version 2.0.2. Given
|
||||
# Eager loading is supported with polymorphic associations.
|
||||
#
|
||||
# class Address < ActiveRecord::Base
|
||||
# belongs_to :addressable, :polymorphic => true
|
||||
# end
|
||||
#
|
||||
# a call that tries to eager load the addressable model
|
||||
# A call that tries to eager load the addressable model
|
||||
#
|
||||
# Address.find(:all, :include => :addressable) # INVALID
|
||||
# Address.find(:all, :include => :addressable)
|
||||
#
|
||||
# will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent model's type
|
||||
# is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that early query.
|
||||
#
|
||||
# In versions greater than 2.0.2 eager loading in polymorphic associations is supported
|
||||
# thanks to a change in the overall preloading strategy.
|
||||
#
|
||||
# It does work the other way around though: if the <tt>User</tt> model is <tt>addressable</tt> you can eager load
|
||||
# their addresses with <tt>:include</tt> just fine, every piece needed to construct the query is known beforehand.
|
||||
# will execute one query to load the addresses and load the addressables with one query per addressable type.
|
||||
# For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of
|
||||
# addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback
|
||||
# to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent
|
||||
# model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query.
|
||||
#
|
||||
# == Table Aliasing
|
||||
#
|
||||
# ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once,
|
||||
# Active Record uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once,
|
||||
# the standard table name is used. The second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>. Indexes are appended
|
||||
# for any more successive uses of the table name.
|
||||
#
|
||||
# Post.find :all, :include => :comments
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ...
|
||||
# Post.find :all, :include => :special_comments # STI
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment'
|
||||
# Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts
|
||||
# Post.find :all, :joins => :comments
|
||||
# # => SELECT ... FROM posts INNER JOIN comments ON ...
|
||||
# Post.find :all, :joins => :special_comments # STI
|
||||
# # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment'
|
||||
# Post.find :all, :joins => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
|
||||
# # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts
|
||||
#
|
||||
# Acts as tree example:
|
||||
#
|
||||
# TreeMixin.find :all, :include => :children
|
||||
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
||||
# TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes
|
||||
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
||||
# LEFT OUTER JOIN parents_mixins ...
|
||||
# TreeMixin.find :all, :include => {:children => {:parent => :children}}
|
||||
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
||||
# LEFT OUTER JOIN parents_mixins ...
|
||||
# LEFT OUTER JOIN mixins childrens_mixins_2
|
||||
# TreeMixin.find :all, :joins => :children
|
||||
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
||||
# TreeMixin.find :all, :joins => {:children => :parent}
|
||||
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
||||
# INNER JOIN parents_mixins ...
|
||||
# TreeMixin.find :all, :joins => {:children => {:parent => :children}}
|
||||
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
||||
# INNER JOIN parents_mixins ...
|
||||
# INNER JOIN mixins childrens_mixins_2
|
||||
#
|
||||
# Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
|
||||
#
|
||||
# Post.find :all, :include => :categories
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
|
||||
# Post.find :all, :include => {:categories => :posts}
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
|
||||
# LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
|
||||
# Post.find :all, :include => {:categories => {:posts => :categories}}
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
|
||||
# LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
|
||||
# LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts
|
||||
# Post.find :all, :joins => :categories
|
||||
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
||||
# Post.find :all, :joins => {:categories => :posts}
|
||||
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
||||
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
||||
# Post.find :all, :joins => {:categories => {:posts => :categories}}
|
||||
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
||||
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
||||
# INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
|
||||
#
|
||||
# If you wish to specify your own custom joins using a <tt>:joins</tt> option, those table names will take precedence over the eager associations:
|
||||
#
|
||||
# Post.find :all, :include => :comments, :joins => "inner join comments ..."
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ...
|
||||
# Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..."
|
||||
# # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ...
|
||||
# LEFT OUTER JOIN comments special_comments_posts ...
|
||||
# Post.find :all, :joins => :comments, :joins => "inner join comments ..."
|
||||
# # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ...
|
||||
# Post.find :all, :joins => [:comments, :special_comments], :joins => "inner join comments ..."
|
||||
# # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ...
|
||||
# INNER JOIN comments special_comments_posts ...
|
||||
# INNER JOIN comments ...
|
||||
#
|
||||
# Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database.
|
||||
|
@ -667,7 +678,7 @@ module ActiveRecord
|
|||
# * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
|
||||
# * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
|
||||
# * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if you, for example, want to do a join
|
||||
# but not include the joined columns.
|
||||
# but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will rise an error.
|
||||
# * <tt>:as</tt> - Specifies a polymorphic interface (See <tt>belongs_to</tt>).
|
||||
# * <tt>:through</tt> - Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
|
||||
# are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a <tt>belongs_to</tt>
|
||||
|
@ -747,12 +758,16 @@ module ActiveRecord
|
|||
# as the default <tt>:foreign_key</tt>.
|
||||
# * <tt>:include</tt> - Specify second-order associations that should be eager loaded when this object is loaded.
|
||||
# * <tt>:as</tt> - Specifies a polymorphic interface (See <tt>belongs_to</tt>).
|
||||
# * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
|
||||
# but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
|
||||
# * <tt>:through</tt>: Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
|
||||
# are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a
|
||||
# <tt>has_one</tt> or <tt>belongs_to</tt> association on the join model.
|
||||
# * <tt>:source</tt> - Specifies the source association name used by <tt>has_one :through</tt> queries. Only use it if the name cannot be
|
||||
# inferred from the association. <tt>has_one :favorite, :through => :favorites</tt> will look for a
|
||||
# <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
|
||||
# * <tt>:source_type</tt> - Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
|
||||
# association is a polymorphic +belongs_to+.
|
||||
# * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
|
||||
#
|
||||
# Option examples:
|
||||
|
@ -819,8 +834,8 @@ module ActiveRecord
|
|||
# if the real class name is Person, you'll have to specify it with this option.
|
||||
# * <tt>:conditions</tt> - Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
||||
# SQL fragment, such as <tt>authorized = 1</tt>.
|
||||
# * <tt>:order</tt> - Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
||||
# such as <tt>last_name, first_name DESC</tt>.
|
||||
# * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
|
||||
# but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
|
||||
# * <tt>:foreign_key</tt> - Specify the foreign key used for the association. By default this is guessed to be the name
|
||||
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt> association will use
|
||||
# "person_id" as the default <tt>:foreign_key</tt>. Similarly, <tt>belongs_to :favorite_person, :class_name => "Person"</tt>
|
||||
|
@ -838,7 +853,6 @@ module ActiveRecord
|
|||
# this results in a counter with +NULL+ value, which will never increment.
|
||||
# Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+.
|
||||
# * <tt>:include</tt> - Specify second-order associations that should be eager loaded when this object is loaded.
|
||||
# Not allowed if the association is polymorphic.
|
||||
# * <tt>:polymorphic</tt> - Specify this association is a polymorphic association by passing +true+.
|
||||
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
||||
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
||||
|
@ -938,7 +952,7 @@ module ActiveRecord
|
|||
#
|
||||
# Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through
|
||||
# +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as
|
||||
# +ReadOnly+ (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any
|
||||
# readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any
|
||||
# associations with attributes to a real join model (see introduction).
|
||||
#
|
||||
# Adds the following methods for retrieval and query:
|
||||
|
@ -1009,7 +1023,7 @@ module ActiveRecord
|
|||
# * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
|
||||
# * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
|
||||
# * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
|
||||
# but not include the joined columns.
|
||||
# but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
|
||||
# * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
|
||||
#
|
||||
# Option examples:
|
||||
|
@ -1339,7 +1353,7 @@ module ActiveRecord
|
|||
|
||||
def create_has_one_reflection(association_id, options)
|
||||
options.assert_valid_keys(
|
||||
:class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly
|
||||
:class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly
|
||||
)
|
||||
|
||||
create_reflection(:has_one, association_id, options, self)
|
||||
|
@ -1347,14 +1361,14 @@ module ActiveRecord
|
|||
|
||||
def create_has_one_through_reflection(association_id, options)
|
||||
options.assert_valid_keys(
|
||||
:class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type
|
||||
:class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type
|
||||
)
|
||||
create_reflection(:has_one, association_id, options, self)
|
||||
end
|
||||
|
||||
def create_belongs_to_reflection(association_id, options)
|
||||
options.assert_valid_keys(
|
||||
:class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent,
|
||||
:class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent,
|
||||
:counter_cache, :extend, :polymorphic, :readonly
|
||||
)
|
||||
|
||||
|
@ -1451,9 +1465,6 @@ module ActiveRecord
|
|||
join_dependency.joins_for_table_name(table)
|
||||
}.flatten.compact.uniq
|
||||
|
||||
|
||||
|
||||
|
||||
is_distinct = !options[:joins].blank? || include_eager_conditions?(options, tables_from_conditions) || include_eager_order?(options, tables_from_order)
|
||||
sql = "SELECT "
|
||||
if is_distinct
|
||||
|
@ -1500,26 +1511,28 @@ module ActiveRecord
|
|||
order.scan(/([\.\w]+).?\./).flatten
|
||||
end
|
||||
|
||||
def selects_tables(options)
|
||||
select = options[:select]
|
||||
return [] unless select && select.is_a?(String)
|
||||
select.scan(/"?([\.\w]+)"?.?\./).flatten
|
||||
end
|
||||
|
||||
# Checks if the conditions reference a table other than the current model table
|
||||
def include_eager_conditions?(options,tables = nil)
|
||||
tables = conditions_tables(options)
|
||||
return false unless tables.any?
|
||||
tables.any? do |condition_table_name|
|
||||
condition_table_name != table_name
|
||||
end
|
||||
def include_eager_conditions?(options, tables = nil)
|
||||
((tables || conditions_tables(options)) - [table_name]).any?
|
||||
end
|
||||
|
||||
# Checks if the query order references a table other than the current model's table.
|
||||
def include_eager_order?(options,tables = nil)
|
||||
tables = order_tables(options)
|
||||
return false unless tables.any?
|
||||
tables.any? do |order_table_name|
|
||||
order_table_name != table_name
|
||||
end
|
||||
def include_eager_order?(options, tables = nil)
|
||||
((tables || order_tables(options)) - [table_name]).any?
|
||||
end
|
||||
|
||||
def include_eager_select?(options)
|
||||
(selects_tables(options) - [table_name]).any?
|
||||
end
|
||||
|
||||
def references_eager_loaded_tables?(options)
|
||||
include_eager_order?(options) || include_eager_conditions?(options)
|
||||
include_eager_order?(options) || include_eager_conditions?(options) || include_eager_select?(options)
|
||||
end
|
||||
|
||||
def using_limitable_reflections?(reflections)
|
||||
|
|
|
@ -48,6 +48,26 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
# Fetches the first one using SQL if possible.
|
||||
def first(*args)
|
||||
if fetch_first_or_last_using_find? args
|
||||
find(:first, *args)
|
||||
else
|
||||
load_target unless loaded?
|
||||
@target.first(*args)
|
||||
end
|
||||
end
|
||||
|
||||
# Fetches the last one using SQL if possible.
|
||||
def last(*args)
|
||||
if fetch_first_or_last_using_find? args
|
||||
find(:last, *args)
|
||||
else
|
||||
load_target unless loaded?
|
||||
@target.last(*args)
|
||||
end
|
||||
end
|
||||
|
||||
def to_ary
|
||||
load_target
|
||||
@target.to_ary
|
||||
|
@ -146,12 +166,18 @@ module ActiveRecord
|
|||
if attrs.is_a?(Array)
|
||||
attrs.collect { |attr| create(attr) }
|
||||
else
|
||||
create_record(attrs) { |record| record.save }
|
||||
create_record(attrs) do |record|
|
||||
yield(record) if block_given?
|
||||
record.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create!(attrs = {})
|
||||
create_record(attrs) { |record| record.save! }
|
||||
create_record(attrs) do |record|
|
||||
yield(record) if block_given?
|
||||
record.save!
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
|
||||
|
@ -330,7 +356,10 @@ module ActiveRecord
|
|||
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def fetch_first_or_last_using_find?(args)
|
||||
args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || !@target.blank? || args.first.kind_of?(Integer))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,7 +49,7 @@ module ActiveRecord
|
|||
alias_method :proxy_respond_to?, :respond_to?
|
||||
alias_method :proxy_extend, :extend
|
||||
delegate :to_param, :to => :proxy_target
|
||||
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ }
|
||||
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
|
||||
|
||||
def initialize(owner, reflection)
|
||||
@owner, @reflection = owner, reflection
|
||||
|
@ -210,7 +210,8 @@ module ActiveRecord
|
|||
|
||||
def raise_on_type_mismatch(record)
|
||||
unless record.is_a?(@reflection.klass)
|
||||
raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.klass} expected, got #{record.class}"
|
||||
message = "#{@reflection.class_name}(##{@reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
|
||||
raise ActiveRecord::AssociationTypeMismatch, message
|
||||
end
|
||||
end
|
||||
|
||||
|
|
5
vendor/rails/activerecord/lib/active_record/associations/belongs_to_association.rb
vendored
Normal file → Executable file
5
vendor/rails/activerecord/lib/active_record/associations/belongs_to_association.rb
vendored
Normal file → Executable file
|
@ -42,10 +42,11 @@ module ActiveRecord
|
|||
private
|
||||
def find_target
|
||||
@reflection.klass.find(
|
||||
@owner[@reflection.primary_key_name],
|
||||
@owner[@reflection.primary_key_name],
|
||||
:select => @reflection.options[:select],
|
||||
:conditions => conditions,
|
||||
:include => @reflection.options[:include],
|
||||
:readonly => @reflection.options[:readonly]
|
||||
:readonly => @reflection.options[:readonly]
|
||||
)
|
||||
end
|
||||
|
||||
|
|
11
vendor/rails/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
vendored
Normal file → Executable file
11
vendor/rails/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
vendored
Normal file → Executable file
|
@ -7,10 +7,8 @@ module ActiveRecord
|
|||
else
|
||||
@target = (AssociationProxy === record ? record.target : record)
|
||||
|
||||
unless record.new_record?
|
||||
@owner[@reflection.primary_key_name] = record.id
|
||||
@owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s
|
||||
end
|
||||
@owner[@reflection.primary_key_name] = record.id
|
||||
@owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s
|
||||
|
||||
@updated = true
|
||||
end
|
||||
|
@ -29,12 +27,13 @@ module ActiveRecord
|
|||
|
||||
if @reflection.options[:conditions]
|
||||
association_class.find(
|
||||
@owner[@reflection.primary_key_name],
|
||||
@owner[@reflection.primary_key_name],
|
||||
:select => @reflection.options[:select],
|
||||
:conditions => conditions,
|
||||
:include => @reflection.options[:include]
|
||||
)
|
||||
else
|
||||
association_class.find(@owner[@reflection.primary_key_name], :include => @reflection.options[:include])
|
||||
association_class.find(@owner[@reflection.primary_key_name], :select => @reflection.options[:select], :include => @reflection.options[:include])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ module ActiveRecord
|
|||
@reflection.klass.count_by_sql(@finder_sql)
|
||||
else
|
||||
column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)
|
||||
options[:conditions] = options[:conditions].nil? ?
|
||||
options[:conditions] = options[:conditions].blank? ?
|
||||
@finder_sql :
|
||||
@finder_sql + " AND (#{sanitize_sql(options[:conditions])})"
|
||||
options[:include] ||= @reflection.options[:include]
|
||||
|
|
|
@ -34,7 +34,7 @@ module ActiveRecord
|
|||
def count(*args)
|
||||
column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)
|
||||
if @reflection.options[:uniq]
|
||||
# This is needed because 'SELECT count(DISTINCT *)..' is not valid sql statement.
|
||||
# This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL statement.
|
||||
column_name = "#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key}" if column_name == :all
|
||||
options.merge!(:distinct => true)
|
||||
end
|
||||
|
@ -237,7 +237,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def build_sti_condition
|
||||
"#{@reflection.through_reflection.quoted_table_name}.#{@reflection.through_reflection.klass.inheritance_column} = #{@reflection.klass.quote_value(@reflection.through_reflection.klass.name.demodulize)}"
|
||||
"#{@reflection.through_reflection.quoted_table_name}.#{@reflection.through_reflection.klass.inheritance_column} = #{@reflection.klass.quote_value(@reflection.through_reflection.klass.sti_name)}"
|
||||
end
|
||||
|
||||
alias_method :sql_conditions, :conditions
|
||||
|
|
5
vendor/rails/activerecord/lib/active_record/associations/has_one_association.rb
vendored
Normal file → Executable file
5
vendor/rails/activerecord/lib/active_record/associations/has_one_association.rb
vendored
Normal file → Executable file
|
@ -51,10 +51,11 @@ module ActiveRecord
|
|||
private
|
||||
def find_target
|
||||
@reflection.klass.find(:first,
|
||||
:conditions => @finder_sql,
|
||||
:conditions => @finder_sql,
|
||||
:select => @reflection.options[:select],
|
||||
:order => @reflection.options[:order],
|
||||
:include => @reflection.options[:include],
|
||||
:readonly => @reflection.options[:readonly]
|
||||
:readonly => @reflection.options[:readonly]
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -16,16 +16,20 @@ module ActiveRecord
|
|||
|
||||
# Declare and check for suffixed attribute methods.
|
||||
module ClassMethods
|
||||
# Declare a method available for all attributes with the given suffix.
|
||||
# Uses method_missing and respond_to? to rewrite the method
|
||||
# Declares a method available for all attributes with the given suffix.
|
||||
# Uses +method_missing+ and <tt>respond_to?</tt> to rewrite the method
|
||||
#
|
||||
# #{attr}#{suffix}(*args, &block)
|
||||
#
|
||||
# to
|
||||
#
|
||||
# attribute#{suffix}(#{attr}, *args, &block)
|
||||
#
|
||||
# An attribute#{suffix} instance method must exist and accept at least
|
||||
# the attr argument.
|
||||
# An <tt>attribute#{suffix}</tt> instance method must exist and accept at least
|
||||
# the +attr+ argument.
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# class Person < ActiveRecord::Base
|
||||
# attribute_method_suffix '_changed?'
|
||||
#
|
||||
|
@ -60,8 +64,8 @@ module ActiveRecord
|
|||
!generated_methods.empty?
|
||||
end
|
||||
|
||||
# generates all the attribute related methods for columns in the database
|
||||
# accessors, mutators and query methods
|
||||
# Generates all the attribute related methods for columns in the database
|
||||
# accessors, mutators and query methods.
|
||||
def define_attribute_methods
|
||||
return if generated_methods?
|
||||
columns_hash.each do |name, column|
|
||||
|
@ -89,8 +93,9 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
# Check to see if the method is defined in the model or any of its subclasses that also derive from ActiveRecord.
|
||||
# Raise DangerousAttributeError if the method is defined by ActiveRecord though.
|
||||
# Checks whether the method is defined in the model or any of its subclasses
|
||||
# that also derive from Active Record. Raises DangerousAttributeError if the
|
||||
# method is defined by Active Record though.
|
||||
def instance_method_already_implemented?(method_name)
|
||||
method_name = method_name.to_s
|
||||
return true if method_name =~ /^id(=$|\?$|$)/
|
||||
|
@ -104,17 +109,19 @@ module ActiveRecord
|
|||
|
||||
# +cache_attributes+ allows you to declare which converted attribute values should
|
||||
# be cached. Usually caching only pays off for attributes with expensive conversion
|
||||
# methods, like date columns (e.g. created_at, updated_at).
|
||||
# methods, like time related columns (e.g. +created_at+, +updated_at+).
|
||||
def cache_attributes(*attribute_names)
|
||||
attribute_names.each {|attr| cached_attributes << attr.to_s}
|
||||
end
|
||||
|
||||
# returns the attributes where
|
||||
# Returns the attributes which are cached. By default time related columns
|
||||
# with datatype <tt>:datetime, :timestamp, :time, :date</tt> are cached.
|
||||
def cached_attributes
|
||||
@cached_attributes ||=
|
||||
columns.select{|c| attribute_types_cached_by_default.include?(c.type)}.map(&:name).to_set
|
||||
end
|
||||
|
||||
# Returns +true+ if the provided attribute is being cached.
|
||||
def cache_attribute?(attr_name)
|
||||
cached_attributes.include?(attr_name)
|
||||
end
|
||||
|
@ -155,6 +162,8 @@ module ActiveRecord
|
|||
evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end"
|
||||
end
|
||||
|
||||
# Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
|
||||
# This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone.
|
||||
def define_read_method_for_time_zone_conversion(attr_name)
|
||||
method_body = <<-EOV
|
||||
def #{attr_name}(reload = false)
|
||||
|
@ -167,7 +176,7 @@ module ActiveRecord
|
|||
evaluate_attribute_method attr_name, method_body
|
||||
end
|
||||
|
||||
# Define an attribute ? method.
|
||||
# Defines a predicate method <tt>attr_name?</tt>.
|
||||
def define_question_method(attr_name)
|
||||
evaluate_attribute_method attr_name, "def #{attr_name}?; query_attribute('#{attr_name}'); end", "#{attr_name}?"
|
||||
end
|
||||
|
@ -176,6 +185,8 @@ module ActiveRecord
|
|||
evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}="
|
||||
end
|
||||
|
||||
# Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
|
||||
# This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone.
|
||||
def define_write_method_for_time_zone_conversion(attr_name)
|
||||
method_body = <<-EOV
|
||||
def #{attr_name}=(time)
|
||||
|
@ -210,14 +221,14 @@ module ActiveRecord
|
|||
end # ClassMethods
|
||||
|
||||
|
||||
# Allows access to the object attributes, which are held in the @attributes hash, as though they
|
||||
# Allows access to the object attributes, which are held in the <tt>@attributes</tt> hash, as though they
|
||||
# were first-class methods. So a Person class with a name attribute can use Person#name and
|
||||
# Person#name= and never directly use the attributes hash -- except for multiple assigns with
|
||||
# ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that
|
||||
# the completed attribute is not nil or 0.
|
||||
# the completed attribute is not +nil+ or 0.
|
||||
#
|
||||
# It's also possible to instantiate related objects, so a Client class belonging to the clients
|
||||
# table with a master_id foreign key can instantiate master through Client#master.
|
||||
# table with a +master_id+ foreign key can instantiate master through Client#master.
|
||||
def method_missing(method_id, *args, &block)
|
||||
method_name = method_id.to_s
|
||||
|
||||
|
@ -288,7 +299,7 @@ module ActiveRecord
|
|||
|
||||
|
||||
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+. Empty strings for fixnum and float
|
||||
# columns are turned into nil.
|
||||
# columns are turned into +nil+.
|
||||
def write_attribute(attr_name, value)
|
||||
attr_name = attr_name.to_s
|
||||
@attributes_cache.delete(attr_name)
|
||||
|
@ -319,8 +330,9 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
# A Person object with a name attribute can ask person.respond_to?("name"), person.respond_to?("name="), and
|
||||
# person.respond_to?("name?") which will all return true.
|
||||
# A Person object with a name attribute can ask <tt>person.respond_to?("name")</tt>,
|
||||
# <tt>person.respond_to?("name=")</tt>, and <tt>person.respond_to?("name?")</tt>
|
||||
# which will all return +true+.
|
||||
alias :respond_to_without_attributes? :respond_to?
|
||||
def respond_to?(method, include_priv = false)
|
||||
method_name = method.to_s
|
||||
|
|
272
vendor/rails/activerecord/lib/active_record/base.rb
vendored
272
vendor/rails/activerecord/lib/active_record/base.rb
vendored
|
@ -2,7 +2,7 @@ require 'yaml'
|
|||
require 'set'
|
||||
|
||||
module ActiveRecord #:nodoc:
|
||||
# Generic ActiveRecord exception class.
|
||||
# Generic Active Record exception class.
|
||||
class ActiveRecordError < StandardError
|
||||
end
|
||||
|
||||
|
@ -30,19 +30,19 @@ module ActiveRecord #:nodoc:
|
|||
class SerializationTypeMismatch < ActiveRecordError
|
||||
end
|
||||
|
||||
# Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field).
|
||||
# Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt> misses adapter field).
|
||||
class AdapterNotSpecified < ActiveRecordError
|
||||
end
|
||||
|
||||
# Raised when ActiveRecord cannot find database adapter specified in config/database.yml or programmatically.
|
||||
# Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
|
||||
class AdapterNotFound < ActiveRecordError
|
||||
end
|
||||
|
||||
# Raised when connection to the database could not been established (for example when connection= is given a nil object).
|
||||
# Raised when connection to the database could not been established (for example when <tt>connection=</tt> is given a nil object).
|
||||
class ConnectionNotEstablished < ActiveRecordError
|
||||
end
|
||||
|
||||
# Raised when ActiveRecord cannot find record by given id or set of ids.
|
||||
# Raised when Active Record cannot find record by given id or set of ids.
|
||||
class RecordNotFound < ActiveRecordError
|
||||
end
|
||||
|
||||
|
@ -70,7 +70,7 @@ module ActiveRecord #:nodoc:
|
|||
# instantiation, for example, when two users edit the same wiki page and one starts editing and saves
|
||||
# the page before the other.
|
||||
#
|
||||
# Read more about optimistic locking in +ActiveRecord::Locking+ module RDoc.
|
||||
# Read more about optimistic locking in ActiveRecord::Locking module RDoc.
|
||||
class StaleObjectError < ActiveRecordError
|
||||
end
|
||||
|
||||
|
@ -83,12 +83,12 @@ module ActiveRecord #:nodoc:
|
|||
class ReadOnlyRecord < ActiveRecordError
|
||||
end
|
||||
|
||||
# Used by ActiveRecord transaction mechanism to distinguish rollback from other exceptional situations.
|
||||
# Used by Active Record transaction mechanism to distinguish rollback from other exceptional situations.
|
||||
# You can use it to roll your transaction back explicitly in the block passed to +transaction+ method.
|
||||
class Rollback < ActiveRecordError
|
||||
end
|
||||
|
||||
# Raised when attribute has a name reserved by ActiveRecord (when attribute has name of one of ActiveRecord instance methods).
|
||||
# Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
|
||||
class DangerousAttributeError < ActiveRecordError
|
||||
end
|
||||
|
||||
|
@ -200,7 +200,7 @@ module ActiveRecord #:nodoc:
|
|||
#
|
||||
# All column values are automatically available through basic accessors on the Active Record object, but sometimes you
|
||||
# want to specialize this behavior. This can be done by overwriting the default accessors (using the same
|
||||
# name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things.
|
||||
# name as the attribute) and calling <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually change things.
|
||||
# Example:
|
||||
#
|
||||
# class Song < ActiveRecord::Base
|
||||
|
@ -215,8 +215,8 @@ module ActiveRecord #:nodoc:
|
|||
# end
|
||||
# end
|
||||
#
|
||||
# You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and
|
||||
# read_attribute(:attribute) as a shorter form.
|
||||
# You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt> instead of <tt>write_attribute(:attribute, value)</tt> and
|
||||
# <tt>read_attribute(:attribute)</tt> as a shorter form.
|
||||
#
|
||||
# == Attribute query methods
|
||||
#
|
||||
|
@ -236,7 +236,7 @@ module ActiveRecord #:nodoc:
|
|||
#
|
||||
# Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first.
|
||||
# That can be done by using the <tt><attribute>_before_type_cast</tt> accessors that all attributes have. For example, if your Account model
|
||||
# has a balance attribute, you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
|
||||
# has a <tt>balance</tt> attribute, you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
|
||||
#
|
||||
# This is especially useful in validation situations where the user might supply a string for an integer field and you want to display
|
||||
# the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you
|
||||
|
@ -245,8 +245,8 @@ module ActiveRecord #:nodoc:
|
|||
# == Dynamic attribute-based finders
|
||||
#
|
||||
# Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by
|
||||
# appending the name of an attribute to <tt>find_by_</tt> or <tt>find_all_by_</tt>, so you get finders like Person.find_by_user_name,
|
||||
# Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing
|
||||
# appending the name of an attribute to <tt>find_by_</tt> or <tt>find_all_by_</tt>, so you get finders like <tt>Person.find_by_user_name</tt>,
|
||||
# <tt>Person.find_all_by_last_name</tt>, and <tt>Payment.find_by_transaction_id</tt>. So instead of writing
|
||||
# <tt>Person.find(:first, :conditions => ["user_name = ?", user_name])</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
|
||||
# And instead of writing <tt>Person.find(:all, :conditions => ["last_name = ?", last_name])</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>.
|
||||
#
|
||||
|
@ -255,8 +255,8 @@ module ActiveRecord #:nodoc:
|
|||
# <tt>Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password])</tt>, you just do
|
||||
# <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
|
||||
#
|
||||
# It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount
|
||||
# is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is
|
||||
# It's even possible to use all the additional parameters to find. For example, the full interface for <tt>Payment.find_all_by_amount</tt>
|
||||
# is actually <tt>Payment.find_all_by_amount(amount, options)</tt>. And the full interface to <tt>Person.find_by_user_name</tt> is
|
||||
# actually <tt>Person.find_by_user_name(user_name, options)</tt>. So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>.
|
||||
#
|
||||
# The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
|
||||
|
@ -316,8 +316,8 @@ module ActiveRecord #:nodoc:
|
|||
# class Client < Company; end
|
||||
# class PriorityClient < Client; end
|
||||
#
|
||||
# When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then
|
||||
# fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object.
|
||||
# When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in the companies table with type = "Firm". You can then
|
||||
# fetch this row again using <tt>Company.find(:first, "name = '37signals'")</tt> and it will return a Firm object.
|
||||
#
|
||||
# If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just
|
||||
# like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
|
||||
|
@ -329,8 +329,8 @@ module ActiveRecord #:nodoc:
|
|||
#
|
||||
# Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection.
|
||||
# All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection.
|
||||
# For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection
|
||||
# and Course *and all its subclasses* will use this connection instead.
|
||||
# For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
|
||||
# and Course and all of its subclasses will use this connection instead.
|
||||
#
|
||||
# This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is
|
||||
# requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
|
||||
|
@ -407,7 +407,7 @@ module ActiveRecord #:nodoc:
|
|||
@@table_name_suffix = ""
|
||||
|
||||
# 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+.
|
||||
# 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.
|
||||
cattr_accessor :pluralize_table_names, :instance_writer => false
|
||||
@@pluralize_table_names = true
|
||||
|
@ -438,40 +438,52 @@ module ActiveRecord #:nodoc:
|
|||
# adapters for, e.g., your development and test environments.
|
||||
cattr_accessor :schema_format , :instance_writer => false
|
||||
@@schema_format = :ruby
|
||||
|
||||
|
||||
# Determine whether to store the full constant name including namespace when using STI
|
||||
superclass_delegating_accessor :store_full_sti_class
|
||||
self.store_full_sti_class = false
|
||||
|
||||
class << self # Class methods
|
||||
# Find operates with four different retrieval approaches:
|
||||
#
|
||||
# * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
|
||||
# * Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
|
||||
# If no record can be found for all of the listed ids, then RecordNotFound will be raised.
|
||||
# * Find first: This will return the first record matched by the options used. These options can either be specific
|
||||
# conditions or merely an order. If no record can be matched, nil is returned.
|
||||
# * Find last: This will return the last record matched by the options used. These options can either be specific
|
||||
# conditions or merely an order. If no record can be matched, nil is returned.
|
||||
# * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned.
|
||||
# * Find first - This will return the first record matched by the options used. These options can either be specific
|
||||
# conditions or merely an order. If no record can be matched, +nil+ is returned. Use
|
||||
# <tt>Model.find(:first, *args)</tt> or its shortcut <tt>Model.first(*args)</tt>.
|
||||
# * Find last - This will return the last record matched by the options used. These options can either be specific
|
||||
# conditions or merely an order. If no record can be matched, +nil+ is returned. Use
|
||||
# <tt>Model.find(:last, *args)</tt> or its shortcut <tt>Model.last(*args)</tt>.
|
||||
# * Find all - This will return all the records matched by the options used.
|
||||
# If no records are found, an empty array is returned. Use
|
||||
# <tt>Model.find(:all, *args)</tt> or its shortcut <tt>Model.all(*args)</tt>.
|
||||
#
|
||||
# All approaches accept an options hash as their last parameter. The options are:
|
||||
# All approaches accept an options hash as their last parameter.
|
||||
#
|
||||
# * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
|
||||
# * <tt>:order</tt>: An SQL fragment like "created_at DESC, name".
|
||||
# * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
|
||||
# * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
|
||||
# * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
|
||||
# * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
|
||||
# or named associations in the same form used for the <tt>:include</tt> option, which will perform an INNER JOIN on the associated table(s).
|
||||
# ==== Attributes
|
||||
#
|
||||
# * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or <tt>[ "user_name = ?", username ]</tt>. See conditions in the intro.
|
||||
# * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
|
||||
# * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
||||
# * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
|
||||
# * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
|
||||
# * <tt>:joins</tt> - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
|
||||
# or named associations in the same form used for the <tt>:include</tt> option, which will perform an <tt>INNER JOIN</tt> on the associated table(s).
|
||||
# If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns.
|
||||
# Pass <tt>:readonly => false</tt> to override.
|
||||
# * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
|
||||
# * <tt>:include</tt> - Names associations that should be loaded alongside. The symbols named refer
|
||||
# to already defined associations. See eager loading under Associations.
|
||||
# * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
|
||||
# * <tt>:select</tt> - By default, this is "*" as in "SELECT * FROM", but can be changed if you, for example, want to do a join but not
|
||||
# include the joined columns.
|
||||
# * <tt>:from</tt>: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
|
||||
# * <tt>:from</tt> - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
|
||||
# of a database view).
|
||||
# * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated.
|
||||
# * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
|
||||
# * <tt>:readonly</tt> - Mark the returned records read-only so they cannot be saved or updated.
|
||||
# * <tt>:lock</tt> - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
|
||||
# <tt>:lock => true</tt> gives connection's default exclusive lock, usually "FOR UPDATE".
|
||||
#
|
||||
# Examples for find by id:
|
||||
# ==== Examples
|
||||
#
|
||||
# # find by id
|
||||
# Person.find(1) # returns the object for ID = 1
|
||||
# Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
|
||||
# Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
|
||||
|
@ -482,17 +494,19 @@ module ActiveRecord #:nodoc:
|
|||
# provide since database rows are unordered. Give an explicit <tt>:order</tt>
|
||||
# to ensure the results are sorted.
|
||||
#
|
||||
# Examples for find first:
|
||||
# ==== Examples
|
||||
#
|
||||
# # find first
|
||||
# Person.find(:first) # returns the first object fetched by SELECT * FROM people
|
||||
# Person.find(:first, :conditions => [ "user_name = ?", user_name])
|
||||
# Person.find(:first, :order => "created_on DESC", :offset => 5)
|
||||
#
|
||||
# Examples for find last:
|
||||
# # find last
|
||||
# Person.find(:last) # returns the last object fetched by SELECT * FROM people
|
||||
# Person.find(:last, :conditions => [ "user_name = ?", user_name])
|
||||
# Person.find(:last, :order => "created_on DESC", :offset => 5)
|
||||
#
|
||||
# Examples for find all:
|
||||
# # find all
|
||||
# Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people
|
||||
# Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
|
||||
# Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] }
|
||||
|
@ -500,11 +514,12 @@ module ActiveRecord #:nodoc:
|
|||
# Person.find(:all, :include => [ :account, :friends ])
|
||||
# Person.find(:all, :group => "category")
|
||||
#
|
||||
# Example for find with a lock. Imagine two concurrent transactions:
|
||||
# each will read person.visits == 2, add 1 to it, and save, resulting
|
||||
# in two saves of person.visits = 3. By locking the row, the second
|
||||
# Example for find with a lock: Imagine two concurrent transactions:
|
||||
# each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting
|
||||
# in two saves of <tt>person.visits = 3</tt>. By locking the row, the second
|
||||
# transaction has to wait until the first is finished; we get the
|
||||
# expected person.visits == 4.
|
||||
# expected <tt>person.visits == 4</tt>.
|
||||
#
|
||||
# Person.transaction do
|
||||
# person = Person.find(1, :lock => true)
|
||||
# person.visits += 1
|
||||
|
@ -522,27 +537,26 @@ module ActiveRecord #:nodoc:
|
|||
else find_from_ids(args, options)
|
||||
end
|
||||
end
|
||||
|
||||
# This is an alias for find(:first). You can pass in all the same arguments to this method as you can
|
||||
# to find(:first)
|
||||
|
||||
# A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the
|
||||
# same arguments to this method as you can to <tt>find(:first)</tt>.
|
||||
def first(*args)
|
||||
find(:first, *args)
|
||||
end
|
||||
|
||||
# This is an alias for find(:last). You can pass in all the same arguments to this method as you can
|
||||
# to find(:last)
|
||||
# A convenience wrapper for <tt>find(:last, *args)</tt>. You can pass in all the
|
||||
# same arguments to this method as you can to <tt>find(:last)</tt>.
|
||||
def last(*args)
|
||||
find(:last, *args)
|
||||
end
|
||||
|
||||
|
||||
# This is an alias for find(:all). You can pass in all the same arguments to this method as you can
|
||||
# to find(:all)
|
||||
def all(*args)
|
||||
find(:all, *args)
|
||||
end
|
||||
|
||||
#
|
||||
# Executes a custom sql query against your database and returns all the results. The results will
|
||||
|
||||
# Executes a custom SQL query against your database and returns all the results. The results will
|
||||
# be returned as an array with columns requested encapsulated as attributes of the model you call
|
||||
# this method from. If you call +Product.find_by_sql+ then the results will be returned in a Product
|
||||
# object with the attributes you specified in the SQL query.
|
||||
|
@ -551,13 +565,13 @@ module ActiveRecord #:nodoc:
|
|||
# SELECT will be attributes of the model, whether or not they are columns of the corresponding
|
||||
# table.
|
||||
#
|
||||
# The +sql+ parameter is a full sql query as a string. It will be called as is, there will be
|
||||
# The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
|
||||
# no database agnostic conversions performed. This should be a last resort because using, for example,
|
||||
# MySQL specific terms will lock you to using that particular database engine or require you to
|
||||
# change your call if you switch engines
|
||||
#
|
||||
# ==== Examples
|
||||
# # A simple sql query spanning multiple tables
|
||||
# # A simple SQL query spanning multiple tables
|
||||
# Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
|
||||
# > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
|
||||
#
|
||||
|
@ -587,10 +601,10 @@ module ActiveRecord #:nodoc:
|
|||
def exists?(id_or_conditions)
|
||||
connection.select_all(
|
||||
construct_finder_sql(
|
||||
:select => "#{quoted_table_name}.#{primary_key}",
|
||||
:conditions => expand_id_conditions(id_or_conditions),
|
||||
:select => "#{quoted_table_name}.#{primary_key}",
|
||||
:conditions => expand_id_conditions(id_or_conditions),
|
||||
:limit => 1
|
||||
),
|
||||
),
|
||||
"#{name} Exists"
|
||||
).size > 0
|
||||
end
|
||||
|
@ -616,7 +630,7 @@ module ActiveRecord #:nodoc:
|
|||
# # Creating an Array of new objects using a block, where the block is executed for each object:
|
||||
# User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
|
||||
# u.is_admin = false
|
||||
# end
|
||||
# end
|
||||
def create(attributes = nil, &block)
|
||||
if attributes.is_a?(Array)
|
||||
attributes.collect { |attr| create(attr, &block) }
|
||||
|
@ -856,9 +870,15 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
|
||||
|
||||
# Attributes named in this macro are protected from mass-assignment, such as <tt>new(attributes)</tt> and
|
||||
# <tt>attributes=(attributes)</tt>. Their assignment will simply be ignored. Instead, you can use the direct writer
|
||||
# methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example:
|
||||
# Attributes named in this macro are protected from mass-assignment,
|
||||
# such as <tt>new(attributes)</tt>,
|
||||
# <tt>update_attributes(attributes)</tt>, or
|
||||
# <tt>attributes=(attributes)</tt>.
|
||||
#
|
||||
# Mass-assignment to these attributes will simply be ignored, to assign
|
||||
# to them you can use direct writer methods. This is meant to protect
|
||||
# sensitive attributes from being overwritten by malicious users
|
||||
# tampering with URLs or forms.
|
||||
#
|
||||
# class Customer < ActiveRecord::Base
|
||||
# attr_protected :credit_rating
|
||||
|
@ -872,7 +892,8 @@ module ActiveRecord #:nodoc:
|
|||
# customer.credit_rating = "Average"
|
||||
# customer.credit_rating # => "Average"
|
||||
#
|
||||
# To start from an all-closed default and enable attributes as needed, have a look at attr_accessible.
|
||||
# To start from an all-closed default and enable attributes as needed,
|
||||
# have a look at +attr_accessible+.
|
||||
def attr_protected(*attributes)
|
||||
write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || []))
|
||||
end
|
||||
|
@ -882,19 +903,18 @@ module ActiveRecord #:nodoc:
|
|||
read_inheritable_attribute("attr_protected")
|
||||
end
|
||||
|
||||
# Similar to the attr_protected macro, this protects attributes of your model from mass-assignment,
|
||||
# such as <tt>new(attributes)</tt> and <tt>attributes=(attributes)</tt>
|
||||
# however, it does it in the opposite way. This locks all attributes and only allows access to the
|
||||
# attributes specified. Assignment to attributes not in this list will be ignored and need to be set
|
||||
# using the direct writer methods instead. This is meant to protect sensitive attributes from being
|
||||
# overwritten by URL/form hackers. If you'd rather start from an all-open default and restrict
|
||||
# attributes as needed, have a look at attr_protected.
|
||||
# Specifies a white list of model attributes that can be set via
|
||||
# mass-assignment, such as <tt>new(attributes)</tt>,
|
||||
# <tt>update_attributes(attributes)</tt>, or
|
||||
# <tt>attributes=(attributes)</tt>
|
||||
#
|
||||
# ==== Attributes
|
||||
#
|
||||
# * <tt>*attributes</tt> A comma separated list of symbols that represent columns _not_ to be protected
|
||||
#
|
||||
# ==== Examples
|
||||
# This is the opposite of the +attr_protected+ macro: Mass-assignment
|
||||
# will only set attributes in this list, to assign to the rest of
|
||||
# attributes you can use direct writer methods. This is meant to protect
|
||||
# sensitive attributes from being overwritten by malicious users
|
||||
# tampering with URLs or forms. If you'd rather start from an all-open
|
||||
# default and restrict attributes as needed, have a look at
|
||||
# +attr_protected+.
|
||||
#
|
||||
# class Customer < ActiveRecord::Base
|
||||
# attr_accessible :name, :nickname
|
||||
|
@ -929,7 +949,7 @@ module ActiveRecord #:nodoc:
|
|||
# If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object,
|
||||
# then specify the name of that attribute using this method and it will be handled automatically.
|
||||
# The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that
|
||||
# class on retrieval or +SerializationTypeMismatch+ will be raised.
|
||||
# class on retrieval or SerializationTypeMismatch will be raised.
|
||||
#
|
||||
# ==== Attributes
|
||||
#
|
||||
|
@ -952,12 +972,14 @@ module ActiveRecord #:nodoc:
|
|||
|
||||
|
||||
# Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
|
||||
# directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used
|
||||
# directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used
|
||||
# to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class
|
||||
# in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb.
|
||||
#
|
||||
# Nested classes are given table names prefixed by the singular form of
|
||||
# the parent's table name. Enclosing modules are not considered. Examples:
|
||||
# the parent's table name. Enclosing modules are not considered.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# class Invoice < ActiveRecord::Base; end;
|
||||
# file class table_name
|
||||
|
@ -971,8 +993,8 @@ module ActiveRecord #:nodoc:
|
|||
# file class table_name
|
||||
# invoice/lineitem.rb Invoice::Lineitem lineitems
|
||||
#
|
||||
# Additionally, the class-level table_name_prefix is prepended and the
|
||||
# table_name_suffix is appended. So if you have "myapp_" as a prefix,
|
||||
# Additionally, the class-level +table_name_prefix+ is prepended and the
|
||||
# +table_name_suffix+ is appended. So if you have "myapp_" as a prefix,
|
||||
# the table name guess for an Invoice class becomes "myapp_invoices".
|
||||
# Invoice::Lineitem becomes "myapp_invoice_lineitems".
|
||||
#
|
||||
|
@ -1023,9 +1045,9 @@ module ActiveRecord #:nodoc:
|
|||
key = 'id'
|
||||
case primary_key_prefix_type
|
||||
when :table_name
|
||||
key = Inflector.foreign_key(base_name, false)
|
||||
key = base_name.to_s.foreign_key(false)
|
||||
when :table_name_with_underscore
|
||||
key = Inflector.foreign_key(base_name)
|
||||
key = base_name.to_s.foreign_key
|
||||
end
|
||||
key
|
||||
end
|
||||
|
@ -1051,8 +1073,6 @@ module ActiveRecord #:nodoc:
|
|||
# Sets the table name to use to the given value, or (if the value
|
||||
# is nil or false) to the value returned by the given block.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class Project < ActiveRecord::Base
|
||||
# set_table_name "project"
|
||||
# end
|
||||
|
@ -1065,8 +1085,6 @@ module ActiveRecord #:nodoc:
|
|||
# or (if the value is nil or false) to the value returned by the given
|
||||
# block.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class Project < ActiveRecord::Base
|
||||
# set_primary_key "sysid"
|
||||
# end
|
||||
|
@ -1079,8 +1097,6 @@ module ActiveRecord #:nodoc:
|
|||
# or (if the value # is nil or false) to the value returned by the
|
||||
# given block.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class Project < ActiveRecord::Base
|
||||
# set_inheritance_column do
|
||||
# original_inheritance_column + "_id"
|
||||
|
@ -1102,8 +1118,6 @@ module ActiveRecord #:nodoc:
|
|||
# If a sequence name is not explicitly set when using PostgreSQL, it
|
||||
# will discover the sequence corresponding to your primary key for you.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class Project < ActiveRecord::Base
|
||||
# set_sequence_name "projectseq" # default would have been "project_seq"
|
||||
# end
|
||||
|
@ -1263,7 +1277,7 @@ module ActiveRecord #:nodoc:
|
|||
class_of_active_record_descendant(self)
|
||||
end
|
||||
|
||||
# Set this to true if this is an abstract class (see #abstract_class?).
|
||||
# Set this to true if this is an abstract class (see <tt>abstract_class?</tt>).
|
||||
attr_accessor :abstract_class
|
||||
|
||||
# Returns whether this class is a base AR class. If A is a base class and
|
||||
|
@ -1279,6 +1293,10 @@ module ActiveRecord #:nodoc:
|
|||
super
|
||||
end
|
||||
|
||||
def sti_name
|
||||
store_full_sti_class ? name : name.demodulize
|
||||
end
|
||||
|
||||
private
|
||||
def find_initial(options)
|
||||
options.update(:limit => 1)
|
||||
|
@ -1298,7 +1316,7 @@ module ActiveRecord #:nodoc:
|
|||
scoped_order = reverse_sql_order(scope(:find, :order))
|
||||
scoped_methods.select { |s| s[:find].update(:order => scoped_order) }
|
||||
end
|
||||
|
||||
|
||||
find_initial(options.merge({ :order => order }))
|
||||
end
|
||||
|
||||
|
@ -1308,12 +1326,12 @@ module ActiveRecord #:nodoc:
|
|||
s.gsub!(/\s(asc|ASC)$/, ' DESC')
|
||||
elsif s.match(/\s(desc|DESC)$/)
|
||||
s.gsub!(/\s(desc|DESC)$/, ' ASC')
|
||||
elsif !s.match(/\s(asc|ASC|desc|DESC)$/)
|
||||
elsif !s.match(/\s(asc|ASC|desc|DESC)$/)
|
||||
s.concat(' DESC')
|
||||
end
|
||||
}.join(',')
|
||||
end
|
||||
|
||||
|
||||
def find_every(options)
|
||||
include_associations = merge_includes(scope(:find, :include), options[:include])
|
||||
|
||||
|
@ -1438,12 +1456,16 @@ module ActiveRecord #:nodoc:
|
|||
# Nest the type name in the same module as this class.
|
||||
# Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo
|
||||
def type_name_with_module(type_name)
|
||||
(/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}"
|
||||
if store_full_sti_class
|
||||
type_name
|
||||
else
|
||||
(/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def construct_finder_sql(options)
|
||||
scope = scope(:find)
|
||||
sql = "SELECT #{(scope && scope[:select]) || options[:select] || (options[:joins] && quoted_table_name + '.*') || '*'} "
|
||||
sql = "SELECT #{options[:select] || (scope && scope[:select]) || (options[:joins] && quoted_table_name + '.*') || '*'} "
|
||||
sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
|
||||
|
||||
add_joins!(sql, options, scope)
|
||||
|
@ -1557,8 +1579,8 @@ module ActiveRecord #:nodoc:
|
|||
|
||||
def type_condition
|
||||
quoted_inheritance_column = connection.quote_column_name(inheritance_column)
|
||||
type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{name.demodulize}' ") do |condition, subclass|
|
||||
condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.name.demodulize}' "
|
||||
type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{sti_name}' ") do |condition, subclass|
|
||||
condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.sti_name}' "
|
||||
end
|
||||
|
||||
" (#{type_condition}) "
|
||||
|
@ -1566,8 +1588,8 @@ module ActiveRecord #:nodoc:
|
|||
|
||||
# Guesses the table name, but does not decorate it with prefix and suffix information.
|
||||
def undecorated_table_name(class_name = base_class.name)
|
||||
table_name = Inflector.underscore(Inflector.demodulize(class_name))
|
||||
table_name = Inflector.pluralize(table_name) if pluralize_table_names
|
||||
table_name = class_name.to_s.demodulize.underscore
|
||||
table_name = table_name.pluralize if pluralize_table_names
|
||||
table_name
|
||||
end
|
||||
|
||||
|
@ -1616,7 +1638,7 @@ module ActiveRecord #:nodoc:
|
|||
self.class_eval %{
|
||||
def self.#{method_id}(*args)
|
||||
guard_protected_attributes = false
|
||||
|
||||
|
||||
if args[0].is_a?(Hash)
|
||||
guard_protected_attributes = true
|
||||
attributes = args[0].with_indifferent_access
|
||||
|
@ -1629,7 +1651,7 @@ module ActiveRecord #:nodoc:
|
|||
set_readonly_option!(options)
|
||||
|
||||
record = find_initial(options)
|
||||
|
||||
|
||||
if record.nil?
|
||||
record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) }
|
||||
#{'yield(record) if block_given?'}
|
||||
|
@ -1710,8 +1732,8 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
|
||||
|
||||
# Defines an "attribute" method (like #inheritance_column or
|
||||
# #table_name). A new (class) method will be created with the
|
||||
# Defines an "attribute" method (like +inheritance_column+ or
|
||||
# +table_name+). A new (class) method will be created with the
|
||||
# given name. If a value is specified, the new method will
|
||||
# return that value (as a string). Otherwise, the given block
|
||||
# will be used to compute the value of the method.
|
||||
|
@ -1888,7 +1910,7 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
# Returns the class descending directly from ActiveRecord in the inheritance hierarchy.
|
||||
# Returns the class descending directly from Active Record in the inheritance hierarchy.
|
||||
def class_of_active_record_descendant(klass)
|
||||
if klass.superclass == Base || klass.superclass.abstract_class?
|
||||
klass
|
||||
|
@ -1899,12 +1921,12 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
# Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy.
|
||||
# Returns the name of the class descending directly from Active Record in the inheritance hierarchy.
|
||||
def class_name_of_active_record_descendant(klass) #:nodoc:
|
||||
klass.base_class.name
|
||||
end
|
||||
|
||||
# Accepts an array, hash, or string of sql conditions and sanitizes
|
||||
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
||||
# them into a valid SQL fragment for a WHERE clause.
|
||||
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
|
||||
# { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
|
||||
|
@ -1920,7 +1942,7 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
alias_method :sanitize_sql, :sanitize_sql_for_conditions
|
||||
|
||||
# Accepts an array, hash, or string of sql conditions and sanitizes
|
||||
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
||||
# them into a valid SQL fragment for a SET clause.
|
||||
# { :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'"
|
||||
def sanitize_sql_for_assignment(assignments)
|
||||
|
@ -1936,7 +1958,7 @@ module ActiveRecord #:nodoc:
|
|||
mapping.first.is_a?(Array) ? mapping : [mapping]
|
||||
end
|
||||
|
||||
# Accepts a hash of sql conditions and replaces those attributes
|
||||
# Accepts a hash of SQL conditions and replaces those attributes
|
||||
# that correspond to a +composed_of+ relationship with their expanded
|
||||
# aggregate attribute values.
|
||||
# Given:
|
||||
|
@ -2009,7 +2031,7 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
|
||||
# Accepts an array of conditions. The array has each value
|
||||
# sanitized and interpolated into the sql statement.
|
||||
# sanitized and interpolated into the SQL statement.
|
||||
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
|
||||
def sanitize_sql_array(ary)
|
||||
statement, *values = ary
|
||||
|
@ -2129,14 +2151,16 @@ module ActiveRecord #:nodoc:
|
|||
# We can't use alias_method here, because method 'id' optimizes itself on the fly.
|
||||
(id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes
|
||||
end
|
||||
|
||||
# Returns a cache key that can be used to identify this record. Examples:
|
||||
|
||||
# Returns a cache key that can be used to identify this record.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# Product.new.cache_key # => "products/new"
|
||||
# Product.find(5).cache_key # => "products/5" (updated_at not available)
|
||||
# Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
|
||||
def cache_key
|
||||
case
|
||||
case
|
||||
when new_record?
|
||||
"#{self.class.name.tableize}/new"
|
||||
when self[:updated_at]
|
||||
|
@ -2170,7 +2194,7 @@ module ActiveRecord #:nodoc:
|
|||
# Note: If your model specifies any validations then the method declaration dynamically
|
||||
# changes to:
|
||||
# save(perform_validation=true)
|
||||
# Calling save(false) saves the model without running validations.
|
||||
# Calling save(false) saves the model without running validations.
|
||||
# See ActiveRecord::Validations for more information.
|
||||
def save
|
||||
create_or_update
|
||||
|
@ -2486,13 +2510,13 @@ module ActiveRecord #:nodoc:
|
|||
id
|
||||
end
|
||||
|
||||
# Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord descendent.
|
||||
# Considering the hierarchy Reply < Message < ActiveRecord, this makes it possible to do Reply.new without having to
|
||||
# set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the
|
||||
# Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendent.
|
||||
# Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to
|
||||
# set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself. No such attribute would be set for objects of the
|
||||
# Message class in that example.
|
||||
def ensure_proper_type
|
||||
unless self.class.descends_from_active_record?
|
||||
write_attribute(self.class.inheritance_column, Inflector.demodulize(self.class.name))
|
||||
write_attribute(self.class.inheritance_column, self.class.sti_name)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2560,7 +2584,7 @@ module ActiveRecord #:nodoc:
|
|||
self.class.connection.quote(value, column)
|
||||
end
|
||||
|
||||
# Interpolate custom sql string in instance context.
|
||||
# Interpolate custom SQL string in instance context.
|
||||
# Optional record argument is meant for custom insert_sql.
|
||||
def interpolate_sql(sql, record = nil)
|
||||
instance_eval("%@#{sql.gsub('@', '\@')}@")
|
||||
|
|
|
@ -46,28 +46,28 @@ module ActiveRecord
|
|||
calculate(:count, *construct_count_options_from_args(*args))
|
||||
end
|
||||
|
||||
# Calculates the average value on a given column. The value is returned as a float. See #calculate for examples with options.
|
||||
# Calculates the average value on a given column. The value is returned as a float. See +calculate+ for examples with options.
|
||||
#
|
||||
# Person.average('age')
|
||||
def average(column_name, options = {})
|
||||
calculate(:avg, column_name, options)
|
||||
end
|
||||
|
||||
# Calculates the minimum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options.
|
||||
# Calculates the minimum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options.
|
||||
#
|
||||
# Person.minimum('age')
|
||||
def minimum(column_name, options = {})
|
||||
calculate(:min, column_name, options)
|
||||
end
|
||||
|
||||
# Calculates the maximum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options.
|
||||
# Calculates the maximum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options.
|
||||
#
|
||||
# Person.maximum('age')
|
||||
def maximum(column_name, options = {})
|
||||
calculate(:max, column_name, options)
|
||||
end
|
||||
|
||||
# Calculates the sum of values on a given column. The value is returned with the same data type of the column. See #calculate for examples with options.
|
||||
# Calculates the sum of values on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options.
|
||||
#
|
||||
# Person.sum('age')
|
||||
def sum(column_name, options = {})
|
||||
|
@ -245,12 +245,14 @@ module ActiveRecord
|
|||
options.assert_valid_keys(CALCULATIONS_OPTIONS)
|
||||
end
|
||||
|
||||
# Converts a given key to the value that the database adapter returns as
|
||||
# a usable column name.
|
||||
# users.id #=> users_id
|
||||
# sum(id) #=> sum_id
|
||||
# count(distinct users.id) #=> count_distinct_users_id
|
||||
# count(*) #=> count_all
|
||||
# Converts the given keys to the value that the database adapter returns as
|
||||
# a usable column name:
|
||||
#
|
||||
# column_alias_for("users.id") # => "users_id"
|
||||
# column_alias_for("sum(id)") # => "sum_id"
|
||||
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
||||
# column_alias_for("count(*)") # => "count_all"
|
||||
# column_alias_for("count", "id") # => "count_id"
|
||||
def column_alias_for(*keys)
|
||||
connection.table_alias_for(keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_'))
|
||||
end
|
||||
|
|
|
@ -161,7 +161,7 @@ module ActiveRecord
|
|||
# == <tt>before_validation*</tt> returning statements
|
||||
#
|
||||
# If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be aborted and <tt>Base#save</tt> will return +false+.
|
||||
# If <tt>Base#save!</tt> is called it will raise a +RecordNotSaved+ exception.
|
||||
# If Base#save! is called it will raise a RecordNotSaved exception.
|
||||
# Nothing will be appended to the errors object.
|
||||
#
|
||||
# == Canceling callbacks
|
||||
|
|
|
@ -193,7 +193,7 @@ module ActiveRecord
|
|||
# :database => "path/to/dbfile"
|
||||
# )
|
||||
#
|
||||
# Also accepts keys as strings (for parsing from yaml for example):
|
||||
# Also accepts keys as strings (for parsing from YAML for example):
|
||||
#
|
||||
# ActiveRecord::Base.establish_connection(
|
||||
# "adapter" => "sqlite",
|
||||
|
|
|
@ -29,7 +29,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
# Returns an array of arrays containing the field values.
|
||||
# Order is the same as that returned by #columns.
|
||||
# Order is the same as that returned by +columns+.
|
||||
def select_rows(sql, name = nil)
|
||||
raise NotImplementedError, "select_rows is an abstract method"
|
||||
end
|
||||
|
@ -93,7 +93,7 @@ module ActiveRecord
|
|||
# done if the transaction block raises an exception or returns false.
|
||||
def rollback_db_transaction() end
|
||||
|
||||
# Alias for #add_limit_offset!.
|
||||
# Alias for <tt>add_limit_offset!</tt>.
|
||||
def add_limit!(sql, options)
|
||||
add_limit_offset!(sql, options) if options
|
||||
end
|
||||
|
@ -106,11 +106,16 @@ module ActiveRecord
|
|||
# SELECT * FROM suppliers LIMIT 10 OFFSET 50
|
||||
def add_limit_offset!(sql, options)
|
||||
if limit = options[:limit]
|
||||
sql << " LIMIT #{limit}"
|
||||
sql << " LIMIT #{sanitize_limit(limit)}"
|
||||
if offset = options[:offset]
|
||||
sql << " OFFSET #{offset}"
|
||||
sql << " OFFSET #{offset.to_i}"
|
||||
end
|
||||
end
|
||||
sql
|
||||
end
|
||||
|
||||
def sanitize_limit(limit)
|
||||
limit.to_s[/,/] ? limit.split(',').map{ |i| i.to_i }.join(',') : limit.to_i
|
||||
end
|
||||
|
||||
# Appends a locking clause to an SQL statement.
|
||||
|
|
|
@ -16,13 +16,13 @@ module ActiveRecord
|
|||
|
||||
# Instantiates a new column in the table.
|
||||
#
|
||||
# +name+ is the column's name, as in <tt><b>supplier_id</b> int(11)</tt>.
|
||||
# +default+ is the type-casted default value, such as <tt>sales_stage varchar(20) default <b>'new'</b></tt>.
|
||||
# +sql_type+ is only used to extract the column's length, if necessary. For example, <tt>company_name varchar(<b>60</b>)</tt>.
|
||||
# +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
|
||||
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
|
||||
# +sql_type+ is only used to extract the column's length, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>.
|
||||
# +null+ determines if this column allows +NULL+ values.
|
||||
def initialize(name, default, sql_type = nil, null = true)
|
||||
@name, @sql_type, @null = name, sql_type, null
|
||||
@limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type)
|
||||
@limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type)
|
||||
@type = simplified_type(sql_type)
|
||||
@default = extract_default(default)
|
||||
|
||||
|
@ -92,7 +92,7 @@ module ActiveRecord
|
|||
# Returns the human name of the column name.
|
||||
#
|
||||
# ===== Examples
|
||||
# Column.new('sales_stage', ...).human_name #=> 'Sales stage'
|
||||
# Column.new('sales_stage', ...).human_name # => 'Sales stage'
|
||||
def human_name
|
||||
Base.human_attribute_name(@name)
|
||||
end
|
||||
|
@ -172,7 +172,7 @@ module ActiveRecord
|
|||
def new_time(year, mon, mday, hour, min, sec, microsec)
|
||||
# Treat 0000-00-00 00:00:00 as nil.
|
||||
return nil if year.nil? || year == 0
|
||||
|
||||
|
||||
Time.time_with_datetime_fallback(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
|
||||
end
|
||||
|
||||
|
@ -250,11 +250,11 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
|
||||
|
||||
|
||||
def sql_type
|
||||
base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
|
||||
end
|
||||
|
||||
|
||||
def to_sql
|
||||
column_sql = "#{base.quote_column_name(name)} #{sql_type}"
|
||||
add_column_options!(column_sql, :null => null, :default => default) unless type.to_sym == :primary_key
|
||||
|
@ -270,7 +270,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
# Represents a SQL table in an abstract way.
|
||||
# Columns are stored as a ColumnDefinition in the #columns attribute.
|
||||
# Columns are stored as a ColumnDefinition in the +columns+ attribute.
|
||||
class TableDefinition
|
||||
attr_accessor :columns
|
||||
|
||||
|
@ -309,39 +309,39 @@ module ActiveRecord
|
|||
# * <tt>:default</tt> -
|
||||
# The column's default value. Use nil for NULL.
|
||||
# * <tt>:null</tt> -
|
||||
# Allows or disallows +NULL+ values in the column. This option could
|
||||
# Allows or disallows +NULL+ values in the column. This option could
|
||||
# have been named <tt>:null_allowed</tt>.
|
||||
# * <tt>:precision</tt> -
|
||||
# Specifies the precision for a <tt>:decimal</tt> column.
|
||||
# Specifies the precision for a <tt>:decimal</tt> column.
|
||||
# * <tt>:scale</tt> -
|
||||
# Specifies the scale for a <tt>:decimal</tt> column.
|
||||
# Specifies the scale for a <tt>:decimal</tt> column.
|
||||
#
|
||||
# Please be aware of different RDBMS implementations behavior with
|
||||
# <tt>:decimal</tt> columns:
|
||||
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
|
||||
# <tt>:precision</tt>, and makes no comments about the requirements of
|
||||
# <tt>:precision</tt>.
|
||||
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
|
||||
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
|
||||
# Default is (10,0).
|
||||
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
||||
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
||||
# <tt>:scale</tt> [0..infinity]. No default.
|
||||
# * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
|
||||
# * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
|
||||
# Internal storage as strings. No default.
|
||||
# * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
|
||||
# but the maximum supported <tt>:precision</tt> is 16. No default.
|
||||
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
||||
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
||||
# Default is (38,0).
|
||||
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
||||
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
||||
# Default unknown.
|
||||
# * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
|
||||
# * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
|
||||
# Default (9,0). Internal types NUMERIC and DECIMAL have different
|
||||
# storage rules, decimal being better.
|
||||
# * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
||||
# * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
||||
# Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
|
||||
# NUMERIC is 19, and DECIMAL is 38.
|
||||
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
||||
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
||||
# Default (38,0).
|
||||
# * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
||||
# * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
||||
# Default (38,0).
|
||||
# * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
|
||||
#
|
||||
|
@ -350,28 +350,28 @@ module ActiveRecord
|
|||
# == Examples
|
||||
# # Assuming td is an instance of TableDefinition
|
||||
# td.column(:granted, :boolean)
|
||||
# #=> granted BOOLEAN
|
||||
# # granted BOOLEAN
|
||||
#
|
||||
# td.column(:picture, :binary, :limit => 2.megabytes)
|
||||
# #=> picture BLOB(2097152)
|
||||
# # => picture BLOB(2097152)
|
||||
#
|
||||
# td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
|
||||
# #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
|
||||
# # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
|
||||
#
|
||||
# def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
|
||||
# #=> bill_gates_money DECIMAL(15,2)
|
||||
# td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
|
||||
# # => bill_gates_money DECIMAL(15,2)
|
||||
#
|
||||
# def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
|
||||
# #=> sensor_reading DECIMAL(30,20)
|
||||
# td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
|
||||
# # => sensor_reading DECIMAL(30,20)
|
||||
#
|
||||
# # While <tt>:scale</tt> defaults to zero on most databases, it
|
||||
# # probably wouldn't hurt to include it.
|
||||
# def.column(:huge_integer, :decimal, :precision => 30)
|
||||
# #=> huge_integer DECIMAL(30)
|
||||
# td.column(:huge_integer, :decimal, :precision => 30)
|
||||
# # => huge_integer DECIMAL(30)
|
||||
#
|
||||
# == Short-hand examples
|
||||
#
|
||||
# Instead of calling column directly, you can also work with the short-hand definitions for the default types.
|
||||
# Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
|
||||
# They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
|
||||
# in a single statement.
|
||||
#
|
||||
|
@ -394,8 +394,8 @@ module ActiveRecord
|
|||
# t.timestamps
|
||||
# end
|
||||
#
|
||||
# There's a short-hand method for each of the type values declared at the top. And then there's
|
||||
# TableDefinition#timestamps that'll add created_at and updated_at as datetimes.
|
||||
# There's a short-hand method for each of the type values declared at the top. And then there's
|
||||
# TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes.
|
||||
#
|
||||
# TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
|
||||
# column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of options, these will be
|
||||
|
@ -434,13 +434,13 @@ module ActiveRecord
|
|||
def #{column_type}(*args)
|
||||
options = args.extract_options!
|
||||
column_names = args
|
||||
|
||||
|
||||
column_names.each { |name| column(name, '#{column_type}', options) }
|
||||
end
|
||||
EOV
|
||||
end
|
||||
|
||||
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
||||
|
||||
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
||||
# <tt>:updated_at</tt> to the table.
|
||||
def timestamps
|
||||
column(:created_at, :datetime)
|
||||
|
@ -458,7 +458,7 @@ module ActiveRecord
|
|||
alias :belongs_to :references
|
||||
|
||||
# Returns a String whose contents are the column definitions
|
||||
# concatenated together. This string can then be prepended and appended to
|
||||
# concatenated together. This string can then be prepended and appended to
|
||||
# to generate the final SQL to create the table.
|
||||
def to_sql
|
||||
@columns * ', '
|
||||
|
@ -510,15 +510,15 @@ module ActiveRecord
|
|||
|
||||
# Adds a new column to the named table.
|
||||
# See TableDefinition#column for details of the options you can use.
|
||||
# ===== Examples
|
||||
# ====== Creating a simple columns
|
||||
# ===== Example
|
||||
# ====== Creating a simple column
|
||||
# t.column(:name, :string)
|
||||
def column(column_name, type, options = {})
|
||||
@base.add_column(@table_name, column_name, type, options)
|
||||
end
|
||||
|
||||
# Adds a new index to the table. +column_name+ can be a single Symbol, or
|
||||
# an Array of Symbols. See SchemaStatements#add_index
|
||||
# Adds a new index to the table. +column_name+ can be a single Symbol, or
|
||||
# an Array of Symbols. See SchemaStatements#add_index
|
||||
#
|
||||
# ===== Examples
|
||||
# ====== Creating a simple index
|
||||
|
@ -531,8 +531,8 @@ module ActiveRecord
|
|||
@base.add_index(@table_name, column_name, options)
|
||||
end
|
||||
|
||||
# Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#timestamps
|
||||
# ===== Examples
|
||||
# Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#add_timestamps
|
||||
# ===== Example
|
||||
# t.timestamps
|
||||
def timestamps
|
||||
@base.add_timestamps(@table_name)
|
||||
|
@ -547,7 +547,7 @@ module ActiveRecord
|
|||
@base.change_column(@table_name, column_name, type, options)
|
||||
end
|
||||
|
||||
# Sets a new default value for a column. See
|
||||
# Sets a new default value for a column. See SchemaStatements#change_column_default
|
||||
# ===== Examples
|
||||
# t.change_default(:qualification, 'new')
|
||||
# t.change_default(:authorized, 1)
|
||||
|
@ -559,27 +559,27 @@ module ActiveRecord
|
|||
# ===== Examples
|
||||
# t.remove(:qualification)
|
||||
# t.remove(:qualification, :experience)
|
||||
# t.removes(:qualification, :experience)
|
||||
def remove(*column_names)
|
||||
@base.remove_column(@table_name, column_names)
|
||||
end
|
||||
|
||||
# Remove the given index from the table.
|
||||
# Removes the given index from the table.
|
||||
#
|
||||
# Remove the suppliers_name_index in the suppliers table.
|
||||
# ===== Examples
|
||||
# ====== Remove the suppliers_name_index in the suppliers table
|
||||
# t.remove_index :name
|
||||
# Remove the index named accounts_branch_id_index in the accounts table.
|
||||
# ====== Remove the index named accounts_branch_id_index in the accounts table
|
||||
# t.remove_index :column => :branch_id
|
||||
# Remove the index named accounts_branch_id_party_id_index in the accounts table.
|
||||
# ====== Remove the index named accounts_branch_id_party_id_index in the accounts table
|
||||
# t.remove_index :column => [:branch_id, :party_id]
|
||||
# Remove the index named by_branch_party in the accounts table.
|
||||
# ====== Remove the index named by_branch_party in the accounts table
|
||||
# t.remove_index :name => :by_branch_party
|
||||
def remove_index(options = {})
|
||||
@base.remove_index(@table_name, options)
|
||||
end
|
||||
|
||||
# Removes the timestamp columns (created_at and updated_at) from the table.
|
||||
# ===== Examples
|
||||
# ===== Example
|
||||
# t.remove_timestamps
|
||||
def remove_timestamps
|
||||
@base.remove_timestamps(@table_name)
|
||||
|
@ -592,12 +592,11 @@ module ActiveRecord
|
|||
@base.rename_column(@table_name, column_name, new_column_name)
|
||||
end
|
||||
|
||||
# Adds a reference. Optionally adds a +type+ column. <tt>reference</tt>,
|
||||
# <tt>references</tt> and <tt>belongs_to</tt> are all acceptable
|
||||
# ===== Example
|
||||
# Adds a reference. Optionally adds a +type+ column.
|
||||
# <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
|
||||
# ===== Examples
|
||||
# t.references(:goat)
|
||||
# t.references(:goat, :polymorphic => true)
|
||||
# t.references(:goat)
|
||||
# t.belongs_to(:goat)
|
||||
def references(*args)
|
||||
options = args.extract_options!
|
||||
|
@ -609,12 +608,11 @@ module ActiveRecord
|
|||
end
|
||||
alias :belongs_to :references
|
||||
|
||||
# Adds a reference. Optionally removes a +type+ column. <tt>remove_reference</tt>,
|
||||
# <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are all acceptable
|
||||
# ===== Example
|
||||
# t.remove_reference(:goat)
|
||||
# t.remove_reference(:goat, :polymorphic => true)
|
||||
# Removes a reference. Optionally removes a +type+ column.
|
||||
# <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
|
||||
# ===== Examples
|
||||
# t.remove_references(:goat)
|
||||
# t.remove_references(:goat, :polymorphic => true)
|
||||
# t.remove_belongs_to(:goat)
|
||||
def remove_references(*args)
|
||||
options = args.extract_options!
|
||||
|
@ -627,7 +625,7 @@ module ActiveRecord
|
|||
alias :remove_belongs_to :remove_references
|
||||
|
||||
# Adds a column or columns of a specified type
|
||||
# ===== Example
|
||||
# ===== Examples
|
||||
# t.string(:goat)
|
||||
# t.string(:goat, :sheep)
|
||||
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
||||
|
|
|
@ -13,7 +13,7 @@ module ActiveRecord
|
|||
255
|
||||
end
|
||||
|
||||
# Truncates a table alias according to the limits of the current adapter.
|
||||
# Truncates a table alias according to the limits of the current adapter.
|
||||
def table_alias_for(table_name)
|
||||
table_name[0..table_alias_length-1].gsub(/\./, '_')
|
||||
end
|
||||
|
@ -32,7 +32,7 @@ module ActiveRecord
|
|||
def columns(table_name, name = nil) end
|
||||
|
||||
# Creates a new table
|
||||
# There are two ways to work with #create_table. You can use the block
|
||||
# There are two ways to work with +create_table+. You can use the block
|
||||
# form or the regular form, like this:
|
||||
#
|
||||
# === Block form
|
||||
|
@ -152,7 +152,7 @@ module ActiveRecord
|
|||
# t.remove :company
|
||||
# end
|
||||
#
|
||||
# ====== Remove a column
|
||||
# ====== Remove several columns
|
||||
# change_table(:suppliers) do |t|
|
||||
# t.remove :company_id
|
||||
# t.remove :width, :height
|
||||
|
@ -168,7 +168,7 @@ module ActiveRecord
|
|||
def change_table(table_name)
|
||||
yield Table.new(table_name, self)
|
||||
end
|
||||
|
||||
|
||||
# Renames a table.
|
||||
# ===== Example
|
||||
# rename_table('octopuses', 'octopi')
|
||||
|
@ -199,7 +199,7 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
alias :remove_columns :remove_column
|
||||
|
||||
|
||||
# Changes the column's definition according to the new options.
|
||||
# See TableDefinition#column for details of the options you can use.
|
||||
# ===== Examples
|
||||
|
@ -302,7 +302,7 @@ module ActiveRecord
|
|||
def dump_schema_information #:nodoc:
|
||||
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
||||
migrated = select_values("SELECT version FROM #{sm_table}")
|
||||
migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n")
|
||||
migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n")
|
||||
end
|
||||
|
||||
# Should not be called normally, but this operation is non-destructive.
|
||||
|
@ -389,7 +389,7 @@ module ActiveRecord
|
|||
def distinct(columns, order_by)
|
||||
"DISTINCT #{columns}"
|
||||
end
|
||||
|
||||
|
||||
# ORDER BY clause for the passed order option.
|
||||
# PostgreSQL overrides this due to its stricter standards compliance.
|
||||
def add_order_by_for_association_limiting!(sql, options)
|
||||
|
@ -401,17 +401,17 @@ module ActiveRecord
|
|||
# add_timestamps(:suppliers)
|
||||
def add_timestamps(table_name)
|
||||
add_column table_name, :created_at, :datetime
|
||||
add_column table_name, :updated_at, :datetime
|
||||
add_column table_name, :updated_at, :datetime
|
||||
end
|
||||
|
||||
|
||||
# Removes the timestamp columns (created_at and updated_at) from the table definition.
|
||||
# ===== Examples
|
||||
# remove_timestamps(:suppliers)
|
||||
def remove_timestamps(table_name)
|
||||
remove_column table_name, :updated_at
|
||||
remove_column table_name, :created_at
|
||||
remove_column table_name, :updated_at
|
||||
remove_column table_name, :created_at
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def options_include_default?(options)
|
||||
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
||||
|
|
|
@ -128,15 +128,11 @@ module ActiveRecord
|
|||
protected
|
||||
def log(sql, name)
|
||||
if block_given?
|
||||
if @logger and @logger.debug?
|
||||
result = nil
|
||||
seconds = Benchmark.realtime { result = yield }
|
||||
@runtime += seconds
|
||||
log_info(sql, name, seconds)
|
||||
result
|
||||
else
|
||||
yield
|
||||
end
|
||||
result = nil
|
||||
seconds = Benchmark.realtime { result = yield }
|
||||
@runtime += seconds
|
||||
log_info(sql, name, seconds)
|
||||
result
|
||||
else
|
||||
log_info(sql, name, 0)
|
||||
nil
|
||||
|
|
|
@ -776,7 +776,7 @@ module ActiveRecord
|
|||
# Returns an ORDER BY clause for the passed order option.
|
||||
#
|
||||
# PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this
|
||||
# by wrapping the sql as a sub-select and ordering in that query.
|
||||
# by wrapping the +sql+ string as a sub-select and ordering in that query.
|
||||
def add_order_by_for_association_limiting!(sql, options) #:nodoc:
|
||||
return sql if options[:order].blank?
|
||||
|
||||
|
|
|
@ -214,6 +214,10 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
||||
if @connection.respond_to?(:transaction_active?) && @connection.transaction_active?
|
||||
raise StatementInvalid, 'Cannot add columns to a SQLite database while inside a transaction'
|
||||
end
|
||||
|
||||
super(table_name, column_name, type, options)
|
||||
# See last paragraph on http://www.sqlite.org/lang_altertable.html
|
||||
execute "VACUUM"
|
||||
|
|
|
@ -40,9 +40,10 @@ module ActiveRecord
|
|||
base.alias_method_chain :save, :dirty
|
||||
base.alias_method_chain :save!, :dirty
|
||||
base.alias_method_chain :update, :dirty
|
||||
base.alias_method_chain :reload, :dirty
|
||||
|
||||
base.superclass_delegating_accessor :partial_updates
|
||||
base.partial_updates = false
|
||||
base.partial_updates = true
|
||||
end
|
||||
|
||||
# Do any attributes have unsaved changes?
|
||||
|
@ -69,19 +70,26 @@ module ActiveRecord
|
|||
changed.inject({}) { |h, attr| h[attr] = attribute_change(attr); h }
|
||||
end
|
||||
|
||||
|
||||
# Clear changed attributes after they are saved.
|
||||
# Attempts to +save+ the record and clears changed attributes if successful.
|
||||
def save_with_dirty(*args) #:nodoc:
|
||||
save_without_dirty(*args)
|
||||
ensure
|
||||
changed_attributes.clear
|
||||
if status = save_without_dirty(*args)
|
||||
changed_attributes.clear
|
||||
end
|
||||
status
|
||||
end
|
||||
|
||||
# Clear changed attributes after they are saved.
|
||||
# Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
|
||||
def save_with_dirty!(*args) #:nodoc:
|
||||
save_without_dirty!(*args)
|
||||
ensure
|
||||
status = save_without_dirty!(*args)
|
||||
changed_attributes.clear
|
||||
status
|
||||
end
|
||||
|
||||
# <tt>reload</tt> the record and clears changed attributes.
|
||||
def reload_with_dirty(*args) #:nodoc:
|
||||
record = reload_without_dirty(*args)
|
||||
changed_attributes.clear
|
||||
record
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -117,14 +125,7 @@ module ActiveRecord
|
|||
# The attribute already has an unsaved change.
|
||||
unless changed_attributes.include?(attr)
|
||||
old = clone_attribute_value(:read_attribute, attr)
|
||||
|
||||
# Remember the original value if it's different.
|
||||
typecasted = if column = column_for_attribute(attr)
|
||||
column.type_cast(value)
|
||||
else
|
||||
value
|
||||
end
|
||||
changed_attributes[attr] = old unless old == typecasted
|
||||
changed_attributes[attr] = old if field_changed?(attr, old, value)
|
||||
end
|
||||
|
||||
# Carry on.
|
||||
|
@ -138,5 +139,20 @@ module ActiveRecord
|
|||
update_without_dirty
|
||||
end
|
||||
end
|
||||
|
||||
def field_changed?(attr, old, value)
|
||||
if column = column_for_attribute(attr)
|
||||
if column.type == :integer && column.null && old.nil?
|
||||
# For nullable integer columns, NULL gets stored in database for blank (i.e. '') values.
|
||||
# Hence we don't record it as a change if the value changes from nil to ''.
|
||||
value = nil if value.blank?
|
||||
else
|
||||
value = column.type_cast(value)
|
||||
end
|
||||
end
|
||||
|
||||
old != value
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,8 +33,8 @@ end
|
|||
#
|
||||
# Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed
|
||||
# by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
|
||||
# put your files in <your-rails-app>/test/fixtures/). The fixture file ends with the .yml file extension (Rails example:
|
||||
# "<your-rails-app>/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this:
|
||||
# put your files in <tt><your-rails-app>/test/fixtures/</tt>). The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
|
||||
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a YAML fixture file looks like this:
|
||||
#
|
||||
# rubyonrails:
|
||||
# id: 1
|
||||
|
@ -67,7 +67,8 @@ end
|
|||
# = CSV fixtures
|
||||
#
|
||||
# Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored
|
||||
# in a single file, but instead end with the .csv file extension (Rails example: "<your-rails-app>/test/fixtures/web_sites.csv")
|
||||
# in a single file, but instead end with the <tt>.csv</tt> file extension
|
||||
# (Rails example: <tt><your-rails-app>/test/fixtures/web_sites.csv</tt>).
|
||||
#
|
||||
# The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
|
||||
# humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised
|
||||
|
@ -93,11 +94,11 @@ end
|
|||
# This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats.
|
||||
# Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory
|
||||
# appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
|
||||
# put your files in <your-rails-app>/test/fixtures/<your-model-name>/ -- like <your-rails-app>/test/fixtures/web_sites/ for the WebSite
|
||||
# model).
|
||||
# put your files in <tt><your-rails-app>/test/fixtures/<your-model-name>/</tt> --
|
||||
# like <tt><your-rails-app>/test/fixtures/web_sites/</tt> for the WebSite model).
|
||||
#
|
||||
# Each text file placed in this directory represents a "record". Usually these types of fixtures are named without
|
||||
# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the
|
||||
# extensions, but if you are on a Windows machine, you might consider adding <tt>.txt</tt> as the extension. Here's what the
|
||||
# above example might look like:
|
||||
#
|
||||
# web_sites/google
|
||||
|
@ -138,20 +139,20 @@ end
|
|||
#
|
||||
# In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable
|
||||
# of the test case. It is named after the symbol... so, in our example, there would be a hash available called
|
||||
# @web_sites. This is where the "fixture name" comes into play.
|
||||
# <tt>@web_sites</tt>. This is where the "fixture name" comes into play.
|
||||
#
|
||||
# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name.
|
||||
# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics:
|
||||
# On top of that, each record is automatically "found" (using <tt>Model.find(id)</tt>) and placed in the instance variable of its name.
|
||||
# So for the YAML fixtures, we'd get <tt>@rubyonrails</tt> and <tt>@google</tt>, which could be interrogated using regular Active Record semantics:
|
||||
#
|
||||
# # test if the object created from the fixture data has the same attributes as the data itself
|
||||
# def test_find
|
||||
# assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name
|
||||
# end
|
||||
#
|
||||
# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return
|
||||
# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded
|
||||
# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual
|
||||
# fixtures available as instance variables @web_site_1 and @web_site_2.
|
||||
# As seen above, the data hash created from the YAML fixtures would have <tt>@web_sites["rubyonrails"]["url"]</tt> return
|
||||
# "http://www.rubyonrails.org" and <tt>@web_sites["google"]["name"]</tt> would return "Google". The same fixtures, but loaded
|
||||
# from a CSV fixture file, would be accessible via <tt>@web_sites["web_site_1"]["name"] == "Ruby on Rails"</tt> and have the individual
|
||||
# fixtures available as instance variables <tt>@web_site_1</tt> and <tt>@web_site_2</tt>.
|
||||
#
|
||||
# If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.
|
||||
#
|
||||
|
@ -184,7 +185,7 @@ end
|
|||
#
|
||||
# This will create 1000 very simple YAML fixtures.
|
||||
#
|
||||
# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>.
|
||||
# Using ERb, you can also inject dynamic values into your fixtures with inserts like <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
|
||||
# This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable
|
||||
# sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application
|
||||
# is properly testable. Hence, dynamic values in fixtures are to be considered a code smell.
|
||||
|
@ -197,20 +198,20 @@ end
|
|||
# class FooTest < ActiveSupport::TestCase
|
||||
# self.use_transactional_fixtures = true
|
||||
# self.use_instantiated_fixtures = false
|
||||
#
|
||||
#
|
||||
# fixtures :foos
|
||||
#
|
||||
#
|
||||
# def test_godzilla
|
||||
# assert !Foo.find(:all).empty?
|
||||
# Foo.destroy_all
|
||||
# assert Foo.find(:all).empty?
|
||||
# end
|
||||
#
|
||||
#
|
||||
# def test_godzilla_aftermath
|
||||
# assert !Foo.find(:all).empty?
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
# If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
|
||||
# then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
|
||||
#
|
||||
|
@ -257,7 +258,7 @@ end
|
|||
# reginald: # generated id: 324201669
|
||||
# name: Reginald the Pirate
|
||||
#
|
||||
# ActiveRecord looks at the fixture's model class, discovers the correct
|
||||
# Active Record looks at the fixture's model class, discovers the correct
|
||||
# primary key, and generates it right before inserting the fixture
|
||||
# into the database.
|
||||
#
|
||||
|
@ -267,7 +268,7 @@ end
|
|||
# == Label references for associations (belongs_to, has_one, has_many)
|
||||
#
|
||||
# Specifying foreign keys in fixtures can be very fragile, not to
|
||||
# mention difficult to read. Since ActiveRecord can figure out the ID of
|
||||
# mention difficult to read. Since Active Record can figure out the ID of
|
||||
# any fixture from its label, you can specify FK's by label instead of ID.
|
||||
#
|
||||
# === belongs_to
|
||||
|
@ -304,15 +305,15 @@ end
|
|||
# name: George the Monkey
|
||||
# pirate: reginald
|
||||
#
|
||||
# Pow! All is made clear. ActiveRecord reflects on the fixture's model class,
|
||||
# Pow! All is made clear. Active Record reflects on the fixture's model class,
|
||||
# finds all the +belongs_to+ associations, and allows you to specify
|
||||
# a target *label* for the *association* (monkey: george) rather than
|
||||
# a target *id* for the *FK* (monkey_id: 1).
|
||||
# a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
|
||||
#
|
||||
# ==== Polymorphic belongs_to
|
||||
#
|
||||
# Supporting polymorphic relationships is a little bit more complicated, since
|
||||
# ActiveRecord needs to know what type your association is pointing at. Something
|
||||
# Active Record needs to know what type your association is pointing at. Something
|
||||
# like this should look familiar:
|
||||
#
|
||||
# ### in fruit.rb
|
||||
|
@ -332,7 +333,7 @@ end
|
|||
# apple:
|
||||
# eater: george (Monkey)
|
||||
#
|
||||
# Just provide the polymorphic target type and ActiveRecord will take care of the rest.
|
||||
# Just provide the polymorphic target type and Active Record will take care of the rest.
|
||||
#
|
||||
# === has_and_belongs_to_many
|
||||
#
|
||||
|
@ -395,15 +396,15 @@ end
|
|||
#
|
||||
# Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
|
||||
# on George's fixture, but we could've just as easily specified a list
|
||||
# of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on
|
||||
# of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
|
||||
# the fixture's model class and discovers the +has_and_belongs_to_many+
|
||||
# associations.
|
||||
#
|
||||
# == Autofilled timestamp columns
|
||||
#
|
||||
# If your table/model specifies any of ActiveRecord's
|
||||
# standard timestamp columns (created_at, created_on, updated_at, updated_on),
|
||||
# they will automatically be set to Time.now.
|
||||
# If your table/model specifies any of Active Record's
|
||||
# standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
|
||||
# they will automatically be set to <tt>Time.now</tt>.
|
||||
#
|
||||
# If you've set specific values, they'll be left alone.
|
||||
#
|
||||
|
@ -730,7 +731,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
|
|||
reader.each do |row|
|
||||
data = {}
|
||||
row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip }
|
||||
self["#{Inflector::underscore(@class_name)}_#{i+=1}"] = Fixture.new(data, model_class)
|
||||
self["#{@class_name.to_s.underscore}_#{i+=1}"] = Fixture.new(data, model_class)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -854,14 +855,14 @@ module Test #:nodoc:
|
|||
require_dependency file_name
|
||||
rescue LoadError => e
|
||||
# Let's hope the developer has included it himself
|
||||
|
||||
|
||||
# Let's warn in case this is a subdependency, otherwise
|
||||
# subdependency error messages are totally cryptic
|
||||
if ActiveRecord::Base.logger
|
||||
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def require_fixture_classes(table_names = nil)
|
||||
(table_names || fixture_table_names).each do |table_name|
|
||||
file_name = table_name.to_s
|
||||
|
|
|
@ -107,20 +107,20 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
# Is optimistic locking enabled for this table? Returns true if the
|
||||
# #lock_optimistically flag is set to true (which it is, by default)
|
||||
# and the table includes the #locking_column column (defaults to
|
||||
# lock_version).
|
||||
# +lock_optimistically+ flag is set to true (which it is, by default)
|
||||
# and the table includes the +locking_column+ column (defaults to
|
||||
# +lock_version+).
|
||||
def locking_enabled?
|
||||
lock_optimistically && columns_hash[locking_column]
|
||||
end
|
||||
|
||||
# Set the column to use for optimistic locking. Defaults to lock_version.
|
||||
# Set the column to use for optimistic locking. Defaults to +lock_version+.
|
||||
def set_locking_column(value = nil, &block)
|
||||
define_attr_method :locking_column, value, &block
|
||||
value
|
||||
end
|
||||
|
||||
# The version column used for optimistic locking. Defaults to lock_version.
|
||||
# The version column used for optimistic locking. Defaults to +lock_version+.
|
||||
def locking_column
|
||||
reset_locking_column
|
||||
end
|
||||
|
@ -130,12 +130,12 @@ module ActiveRecord
|
|||
connection.quote_column_name(locking_column)
|
||||
end
|
||||
|
||||
# Reset the column used for optimistic locking back to the lock_version default.
|
||||
# Reset the column used for optimistic locking back to the +lock_version+ default.
|
||||
def reset_locking_column
|
||||
set_locking_column DEFAULT_LOCKING_COLUMN
|
||||
end
|
||||
|
||||
# make sure the lock version column gets updated when counters are
|
||||
# Make sure the lock version column gets updated when counters are
|
||||
# updated.
|
||||
def update_counters_with_lock(id, counters)
|
||||
counters = counters.merge(locking_column => 1) if locking_enabled?
|
||||
|
|
|
@ -208,7 +208,7 @@ module ActiveRecord
|
|||
#
|
||||
# You can quiet them down by setting ActiveRecord::Migration.verbose = false.
|
||||
#
|
||||
# You can also insert your own messages and benchmarks by using the #say_with_time
|
||||
# You can also insert your own messages and benchmarks by using the +say_with_time+
|
||||
# method:
|
||||
#
|
||||
# def self.up
|
||||
|
@ -377,7 +377,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def proper_table_name(name)
|
||||
# Use the ActiveRecord objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
|
||||
# Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
|
||||
name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,9 +2,7 @@ module ActiveRecord
|
|||
module NamedScope
|
||||
# All subclasses of ActiveRecord::Base have two named_scopes:
|
||||
# * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and
|
||||
# * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly:
|
||||
#
|
||||
# Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)
|
||||
# * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly: <tt>Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)</tt>
|
||||
#
|
||||
# These anonymous scopes tend to be useful when procedurally generating complex queries, where passing
|
||||
# intermediate values (scopes) around as first-class objects is convenient.
|
||||
|
@ -41,7 +39,7 @@ module ActiveRecord
|
|||
# Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
|
||||
# for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
|
||||
#
|
||||
# All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to
|
||||
# All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to
|
||||
# <tt>has_many</tt> associations. If,
|
||||
#
|
||||
# class Person < ActiveRecord::Base
|
||||
|
@ -102,7 +100,13 @@ module ActiveRecord
|
|||
|
||||
class Scope
|
||||
attr_reader :proxy_scope, :proxy_options
|
||||
[].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ }
|
||||
|
||||
[].methods.each do |m|
|
||||
unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last|empty?)/
|
||||
delegate m, :to => :proxy_found
|
||||
end
|
||||
end
|
||||
|
||||
delegate :scopes, :with_scope, :to => :proxy_scope
|
||||
|
||||
def initialize(proxy_scope, options, &block)
|
||||
|
@ -115,6 +119,26 @@ module ActiveRecord
|
|||
load_found; self
|
||||
end
|
||||
|
||||
def first(*args)
|
||||
if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
|
||||
proxy_found.first(*args)
|
||||
else
|
||||
find(:first, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def last(*args)
|
||||
if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash))
|
||||
proxy_found.last(*args)
|
||||
else
|
||||
find(:last, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def empty?
|
||||
@found ? @found.empty? : count.zero?
|
||||
end
|
||||
|
||||
protected
|
||||
def proxy_found
|
||||
@found || load_found
|
||||
|
@ -136,4 +160,4 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ module ActiveRecord
|
|||
# # Same as above, just using explicit class references
|
||||
# ActiveRecord::Base.observers = Cacher, GarbageCollector
|
||||
#
|
||||
# Note: Setting this does not instantiate the observers yet. #instantiate_observers is
|
||||
# Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is
|
||||
# called during startup, and before each development request.
|
||||
def observers=(*observers)
|
||||
@observers = observers.flatten
|
||||
|
@ -30,7 +30,7 @@ module ActiveRecord
|
|||
@observers ||= []
|
||||
end
|
||||
|
||||
# Instantiate the global ActiveRecord observers
|
||||
# Instantiate the global Active Record observers.
|
||||
def instantiate_observers
|
||||
return if @observers.blank?
|
||||
@observers.each do |observer|
|
||||
|
|
|
@ -30,8 +30,8 @@ module ActiveRecord
|
|||
|
||||
# Eval the given block. All methods available to the current connection
|
||||
# adapter are available within the block, so you can easily use the
|
||||
# database definition DSL to build up your schema (#create_table,
|
||||
# #add_index, etc.).
|
||||
# database definition DSL to build up your schema (+create_table+,
|
||||
# +add_index+, etc.).
|
||||
#
|
||||
# The +info+ hash is optional, and if given is used to define metadata
|
||||
# about the current schema (currently, only the schema's version):
|
||||
|
|
|
@ -38,7 +38,7 @@ module ActiveRecord
|
|||
|
||||
stream.puts <<HEADER
|
||||
# This file is auto-generated from the current state of the database. Instead of editing this file,
|
||||
# please use the migrations feature of ActiveRecord to incrementally modify your database, and
|
||||
# please use the migrations feature of Active Record to incrementally modify your database, and
|
||||
# then regenerate this schema definition.
|
||||
#
|
||||
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
|
||||
|
|
|
@ -273,14 +273,14 @@ module ActiveRecord #:nodoc:
|
|||
end
|
||||
|
||||
# There is a significant speed improvement if the value
|
||||
# does not need to be escaped, as #tag! escapes all values
|
||||
# does not need to be escaped, as <tt>tag!</tt> escapes all values
|
||||
# to ensure that valid XML is generated. For known binary
|
||||
# values, it is at least an order of magnitude faster to
|
||||
# Base64 encode binary values and directly put them in the
|
||||
# output XML than to pass the original value or the Base64
|
||||
# encoded value to the #tag! method. It definitely makes
|
||||
# encoded value to the <tt>tag!</tt> method. It definitely makes
|
||||
# no sense to Base64 encode the value and then give it to
|
||||
# #tag!, since that just adds additional overhead.
|
||||
# <tt>tag!</tt>, since that just adds additional overhead.
|
||||
def needs_encoding?
|
||||
![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type)
|
||||
end
|
||||
|
|
|
@ -30,9 +30,9 @@ module ActiveRecord
|
|||
# Exceptions will force a ROLLBACK that returns the database to the state before the transaction was begun. Be aware, though,
|
||||
# that the objects will _not_ have their instance data returned to their pre-transactional state.
|
||||
#
|
||||
# == Different ActiveRecord classes in a single transaction
|
||||
# == Different Active Record classes in a single transaction
|
||||
#
|
||||
# Though the transaction class method is called on some ActiveRecord class,
|
||||
# Though the transaction class method is called on some Active Record class,
|
||||
# the objects within the transaction block need not all be instances of
|
||||
# that class.
|
||||
# In this example a <tt>Balance</tt> record is transactionally saved even
|
||||
|
|
|
@ -301,7 +301,7 @@ module ActiveRecord
|
|||
:odd => 'odd?', :even => 'even?' }.freeze
|
||||
|
||||
# Adds a validation method or block to the class. This is useful when
|
||||
# overriding the #validate instance method becomes too unwieldly and
|
||||
# overriding the +validate+ instance method becomes too unwieldly and
|
||||
# you're looking for more descriptive declaration of your validations.
|
||||
#
|
||||
# This can be done with a symbol pointing to a method:
|
||||
|
@ -326,7 +326,7 @@ module ActiveRecord
|
|||
# end
|
||||
# end
|
||||
#
|
||||
# This usage applies to #validate_on_create and #validate_on_update as well.
|
||||
# This usage applies to +validate_on_create+ and +validate_on_update+ as well.
|
||||
|
||||
# Validates each attribute against a block.
|
||||
#
|
||||
|
@ -692,7 +692,7 @@ module ActiveRecord
|
|||
raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp)
|
||||
|
||||
validates_each(attr_names, configuration) do |record, attr_name, value|
|
||||
record.errors.add(attr_name, configuration[:message]) unless value.to_s =~ configuration[:with]
|
||||
record.errors.add(attr_name, configuration[:message] % value) unless value.to_s =~ configuration[:with]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
module ActiveRecord
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 0
|
||||
TINY = 991
|
||||
MINOR = 1
|
||||
TINY = 0
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue