aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVijay Dev <vijaydev.cse@gmail.com>2012-06-30 23:15:22 +0530
committerVijay Dev <vijaydev.cse@gmail.com>2012-06-30 23:15:22 +0530
commit6b9d1a0db2f7829509689d244d6a5eda5210401d (patch)
tree2d4920fa5e2f3d8571573d5aee717cac261c53ac
parent4662c5f4effd829099d647a7a76c7044fcc68121 (diff)
parent32c28e8214940fe6b06043b280e8d342e16eb3c6 (diff)
downloadrails-6b9d1a0db2f7829509689d244d6a5eda5210401d.tar.gz
rails-6b9d1a0db2f7829509689d244d6a5eda5210401d.tar.bz2
rails-6b9d1a0db2f7829509689d244d6a5eda5210401d.zip
Merge branch 'master' of github.com:lifo/docrails
Conflicts: activemodel/lib/active_model/errors.rb
-rw-r--r--activemodel/lib/active_model/conversion.rb31
-rw-r--r--activemodel/lib/active_model/dirty.rb6
-rw-r--r--activemodel/lib/active_model/errors.rb191
-rw-r--r--activemodel/lib/active_model/lint.rb45
-rw-r--r--activemodel/lib/active_model/model.rb53
-rw-r--r--activemodel/lib/active_model/naming.rb149
-rw-r--r--activerecord/lib/active_record/associations.rb8
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/hash/except.rb7
-rw-r--r--guides/source/debugging_rails_applications.textile2
-rw-r--r--guides/source/getting_started.textile4
-rw-r--r--guides/source/performance_testing.textile6
-rw-r--r--guides/source/routing.textile8
13 files changed, 385 insertions, 137 deletions
diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb
index d7f30f0920..89d87a8b6f 100644
--- a/activemodel/lib/active_model/conversion.rb
+++ b/activemodel/lib/active_model/conversion.rb
@@ -18,17 +18,23 @@ module ActiveModel
# end
#
# cm = ContactMessage.new
- # cm.to_model == self # => true
- # cm.to_key # => nil
- # cm.to_param # => nil
- # cm.to_partial_path # => "contact_messages/contact_message"
- #
+ # cm.to_model == cm # => true
+ # cm.to_key # => nil
+ # cm.to_param # => nil
+ # cm.to_partial_path # => "contact_messages/contact_message"
module Conversion
extend ActiveSupport::Concern
# If your object is already designed to implement all of the Active Model
# you can use the default <tt>:to_model</tt> implementation, which simply
- # returns self.
+ # returns +self+.
+ #
+ # class Person
+ # include ActiveModel::Conversion
+ # end
+ #
+ # person = Person.new
+ # person.to_model == person # => true
#
# If your model does not act like an Active Model object, then you should
# define <tt>:to_model</tt> yourself returning a proxy object that wraps
@@ -37,21 +43,28 @@ module ActiveModel
self
end
- # Returns an Enumerable of all key attributes if any is set, regardless
- # if the object is persisted or not.
+ # Returns an Enumerable of all key attributes if any is set, regardless if
+ # the object is persisted or not. If there no key attributes, returns +nil+.
def to_key
key = respond_to?(:id) && id
key ? [key] : nil
end
# Returns a string representing the object's key suitable for use in URLs,
- # or nil if <tt>persisted?</tt> is false.
+ # or +nil+ if <tt>persisted?</tt> is false.
def to_param
persisted? ? to_key.join('-') : nil
end
# Returns a string identifying the path associated with the object.
# ActionPack uses this to find a suitable partial to represent the object.
+ #
+ # class Person
+ # include ActiveModel::Conversion
+ # end
+ #
+ # person = Person.new
+ # person.to_partial_path # => "people/person"
def to_partial_path
self.class._to_partial_path
end
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 7014d8114f..9bd5f903cd 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -80,8 +80,8 @@ module ActiveModel
# person.changes # => {"name" => ["Bill", "Bob"]}
#
# If an attribute is modified in-place then make use of <tt>[attribute_name]_will_change!</tt>
- # to mark that the attribute is changing. Otherwise ActiveModel can't track changes to
- # in-place attributes.
+ # to mark that the attribute is changing. Otherwise ActiveModel can't track
+ # changes to in-place attributes.
#
# person.name_will_change!
# person.name_change # => ["Bill", "Bill"]
@@ -115,7 +115,7 @@ module ActiveModel
end
# Returns a hash of changed attributes indicating their original
- # and new values like <tt>attr => [original value, new value]</tt>.
+ # and new values like <tt>attr => [original value, new value]</tt>.
#
# person.changes # => {}
# person.name = 'bob'
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 567677bbb9..4ed3462e7e 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -54,8 +54,8 @@ module ActiveModel
# The above allows you to do:
#
# p = Person.new
- # p.validate! # => ["can not be nil"]
- # p.errors.full_messages # => ["name can not be nil"]
+ # person.validate! # => ["can not be nil"]
+ # person.errors.full_messages # => ["name can not be nil"]
# # etc..
class Errors
include Enumerable
@@ -81,28 +81,50 @@ module ActiveModel
super
end
- # Clear the messages
+ # Clear the error messages.
+ #
+ # person.errors.full_messages # => ["name can not be nil"]
+ # person.errors.clear
+ # person.errors.full_messages # => []
def clear
messages.clear
end
- # Do the error messages include an error with key +error+?
+ # Returns +true+ if the error messages include an error for the given key
+ # +attribute+, +false+ otherwise.
+ #
+ # person.errors.messages # => { :name => ["can not be nil"] }
+ # person.errors.include?(:name) # => true
+ # person.errors.include?(:age) # => false
def include?(attribute)
(v = messages[attribute]) && v.any?
end
+ # aliases include?
alias :has_key? :include?
- # Get messages for +key+
+ # Get messages for +key+.
+ #
+ # person.errors.messages # => { :name => ["can not be nil"] }
+ # person.errors.get(:name) # => ["can not be nil"]
+ # person.errors.get(:age) # => nil
def get(key)
messages[key]
end
- # Set messages for +key+ to +value+
+ # Set messages for +key+ to +value+.
+ #
+ # person.errors.get(:name) # => ["can not be nil"]
+ # person.errors.set(:name, ["can't be nil"])
+ # person.errors.get(:name) # => ["can't be nil"]
def set(key, value)
messages[key] = value
end
- # Delete messages for +key+
+ # Delete messages for +key+. Returns the deleted messages.
+ #
+ # person.errors.get(:name) # => ["can not be nil"]
+ # person.errors.delete(:name) # => ["can not be nil"]
+ # person.errors.get(:name) # => nil
def delete(key)
messages.delete(key)
end
@@ -110,16 +132,16 @@ module ActiveModel
# When passed a symbol or a name of a method, returns an array of errors
# for the method.
#
- # p.errors[:name] # => ["can not be nil"]
- # p.errors['name'] # => ["can not be nil"]
+ # person.errors[:name] # => ["can not be nil"]
+ # person.errors['name'] # => ["can not be nil"]
def [](attribute)
get(attribute.to_sym) || set(attribute.to_sym, [])
end
# Adds to the supplied attribute the supplied error message.
#
- # p.errors[:name] = "must be set"
- # p.errors[:name] # => ['must be set']
+ # person.errors[:name] = "must be set"
+ # person.errors[:name] # => ['must be set']
def []=(attribute, error)
self[attribute] << error
end
@@ -128,13 +150,13 @@ module ActiveModel
# Yields the attribute and the error for that attribute. If the attribute
# has more than one error message, yields once for each error message.
#
- # p.errors.add(:name, "can't be blank")
- # p.errors.each do |attribute, error|
+ # person.errors.add(:name, "can't be blank")
+ # person.errors.each do |attribute, error|
# # Will yield :name and "can't be blank"
# end
#
- # p.errors.add(:name, "must be specified")
- # p.errors.each do |attribute, error|
+ # person.errors.add(:name, "must be specified")
+ # person.errors.each do |attribute, error|
# # Will yield :name and "can't be blank"
# # then yield :name and "must be specified"
# end
@@ -146,54 +168,65 @@ module ActiveModel
# Returns the number of error messages.
#
- # p.errors.add(:name, "can't be blank")
- # p.errors.size # => 1
- # p.errors.add(:name, "must be specified")
- # p.errors.size # => 2
+ # person.errors.add(:name, "can't be blank")
+ # person.errors.size # => 1
+ # person.errors.add(:name, "must be specified")
+ # person.errors.size # => 2
def size
values.flatten.size
end
- # Returns all message values
+ # Returns all message values.
+ #
+ # person.errors.messages # => { :name => ["can not be nil", "must be specified"] }
+ # person.errors.values # => [["can not be nil", "must be specified"]]
def values
messages.values
end
- # Returns all message keys
+ # Returns all message keys.
+ #
+ # person.errors.messages # => { :name => ["can not be nil", "must be specified"] }
+ # person.errors.keys # => [:name]
def keys
messages.keys
end
- # Returns an array of error messages, with the attribute name included
+ # Returns an array of error messages, with the attribute name included.
#
- # p.errors.add(:name, "can't be blank")
- # p.errors.add(:name, "must be specified")
- # p.errors.to_a # => ["name can't be blank", "name must be specified"]
+ # person.errors.add(:name, "can't be blank")
+ # person.errors.add(:name, "must be specified")
+ # person.errors.to_a # => ["name can't be blank", "name must be specified"]
def to_a
full_messages
end
# Returns the number of error messages.
- # p.errors.add(:name, "can't be blank")
- # p.errors.count # => 1
- # p.errors.add(:name, "must be specified")
- # p.errors.count # => 2
+ #
+ # person.errors.add(:name, "can't be blank")
+ # person.errors.count # => 1
+ # person.errors.add(:name, "must be specified")
+ # person.errors.count # => 2
def count
to_a.size
end
- # Returns true if no errors are found, false otherwise.
+ # Returns +true+ if no errors are found, +false+ otherwise.
# If the error message is a string it can be empty.
+ #
+ # person.errors.full_messages # => ["name can not be nil"]
+ # person.errors.empty? # => false
def empty?
all? { |k, v| v && v.empty? && !v.is_a?(String) }
end
+ # aliases empty?
alias_method :blank?, :empty?
# Returns an xml formatted representation of the Errors hash.
#
- # p.errors.add(:name, "can't be blank")
- # p.errors.add(:name, "must be specified")
- # p.errors.to_xml
+ # person.errors.add(:name, "can't be blank")
+ # person.errors.add(:name, "must be specified")
+ # person.errors.to_xml
# # =>
# # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
# # <errors>
@@ -204,14 +237,21 @@ module ActiveModel
to_a.to_xml({ :root => "errors", :skip_types => true }.merge!(options))
end
- # Returns an Hash that can be used as the JSON representation for this object.
- # Options:
- # * <tt>:full_messages</tt> - determines if json object should contain
- # full messages or not. Default: <tt>false</tt>.
+ # Returns a Hash that can be used as the JSON representation for this
+ # object. You can pass the <tt>:full_messages</tt> option. This determines
+ # if the json object should contain full messages or not (false by default).
+ #
+ # person.as_json # => { :name => ["can not be nil"] }
+ # person.as_json(full_messages: true) # => { :name => ["name can not be nil"] }
def as_json(options=nil)
to_hash(options && options[:full_messages])
end
+ # Returns a Hash of attributes with their error messages. If +full_messages+
+ # is +true+, it will contain full messages (see +full_message+).
+ #
+ # person.to_hash # => { :name => ["can not be nil"] }
+ # person.to_hash(true) # => { :name => ["name can not be nil"] }
def to_hash(full_messages = false)
if full_messages
messages = {}
@@ -224,12 +264,31 @@ module ActiveModel
end
end
- # Adds +message+ to the error messages on +attribute+. More than one error can be added to the same
- # +attribute+.
- # If no +message+ is supplied, <tt>:invalid</tt> is assumed.
+ # Adds +message+ to the error messages on +attribute+. More than one error
+ # can be added to the same +attribute+. If no +message+ is supplied,
+ # <tt>:invalid</tt> is assumed.
#
- # If +message+ is a symbol, it will be translated using the appropriate scope (see +generate_message+).
- # If +message+ is a proc, it will be called, allowing for things like <tt>Time.now</tt> to be used within an error.
+ # person.errors.add(:name)
+ # # => ["is invalid"]
+ # person.errors.add(:name, 'must be implemented')
+ # # => ["is invalid", "must be implemented"]
+ #
+ # person.errors.messages
+ # # => { :name => ["must be implemented", "is invalid"] }
+ #
+ # If +message+ is a symbol, it will be translated using the appropriate
+ # scope (see +generate_message+).
+ #
+ # If +message+ is a proc, it will be called, allowing for things like
+ # <tt>Time.now</tt> to be used within an error.
+ #
+ # If the <tt>:strict</tt> option is set to true will raise
+ # ActiveModel::StrictValidationFailed instead of adding the error.
+ #
+ # person.errors.add(:name, nil, strict: true)
+ # # => ActiveModel::StrictValidationFailed: name is invalid
+ #
+ # person.errors.messages # => {}
def add(attribute, message = nil, options = {})
message = normalize_message(attribute, message, options)
if options[:strict]
@@ -239,7 +298,12 @@ module ActiveModel
self[attribute] << message
end
- # Will add an error message to each of the attributes in +attributes+ that is empty.
+ # Will add an error message to each of the attributes in +attributes+
+ # that is empty.
+ #
+ # person.errors.add_on_empty(:name)
+ # person.errors.messages
+ # # => { :name => ["can't be empty"] }
def add_on_empty(attributes, options = {})
[attributes].flatten.each do |attribute|
value = @base.send(:read_attribute_for_validation, attribute)
@@ -248,7 +312,12 @@ module ActiveModel
end
end
- # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?).
+ # Will add an error message to each of the attributes in +attributes+ that
+ # is blank (using Object#blank?).
+ #
+ # person.errors.add_on_blank(:name)
+ # person.errors.messages
+ # # => { :name => ["can't be blank"] }
def add_on_blank(attributes, options = {})
[attributes].flatten.each do |attribute|
value = @base.send(:read_attribute_for_validation, attribute)
@@ -256,10 +325,11 @@ module ActiveModel
end
end
- # Returns true if an error on the attribute with the given message is present, false otherwise.
- # +message+ is treated the same as for +add+.
- # p.errors.add :name, :blank
- # p.errors.added? :name, :blank # => true
+ # Returns +true+ if an error on the attribute with the given message is
+ # present, +false+ otherwise. +message+ is treated the same as for +add+.
+ #
+ # person.errors.add :name, :blank
+ # person.errors.added? :name, :blank # => true
def added?(attribute, message = nil, options = {})
message = normalize_message(attribute, message, options)
self[attribute].include? message
@@ -267,22 +337,21 @@ module ActiveModel
# Returns all the full error messages in an array.
#
- # class Company
+ # class Person
# validates_presence_of :name, :address, :email
- # validates_length_of :name, :in => 5..30
+ # validates_length_of :name, in: 5..30
# end
#
- # company = Company.create(:address => '123 First St.')
- # company.errors.full_messages # =>
- # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
+ # person = Person.create(address: '123 First St.')
+ # person.errors.full_messages
+ # # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
def full_messages
map { |attribute, message| full_message(attribute, message) }
end
# Returns a full message for a given attribute.
#
- # company.errors.full_message(:name, "is invalid") # =>
- # "Name is invalid"
+ # person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
def full_message(attribute, message)
return message if attribute == :base
attr_name = attribute.to_s.tr('.', '_').humanize
@@ -298,10 +367,11 @@ module ActiveModel
# (<tt>activemodel.errors.messages</tt>).
#
# Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
- # if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not
- # there also, it returns the translation of the default message
- # (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model name,
- # translated attribute name and the value are available for interpolation.
+ # if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if
+ # that is not there also, it returns the translation of the default message
+ # (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
+ # name, translated attribute name and the value are available for
+ # interpolation.
#
# When using inheritance in your models, it will check all the inherited
# models too, but only if the model itself hasn't been found. Say you have
@@ -317,7 +387,6 @@ module ActiveModel
# * <tt>activemodel.errors.messages.blank</tt>
# * <tt>errors.attributes.title.blank</tt>
# * <tt>errors.messages.blank</tt>
- #
def generate_message(attribute, type = :invalid, options = {})
type = options.delete(:message) if options[:message].is_a?(Symbol)
@@ -366,6 +435,8 @@ module ActiveModel
end
end
+ # Raised when a validation cannot be corrected by end users and are considered
+ # exceptional.
class StrictValidationFailed < StandardError
end
end
diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb
index 88b730626c..550fa474ea 100644
--- a/activemodel/lib/active_model/lint.rb
+++ b/activemodel/lib/active_model/lint.rb
@@ -12,19 +12,20 @@ module ActiveModel
# you want all features out of the box.
#
# These tests do not attempt to determine the semantic correctness of the
- # returned values. For instance, you could implement valid? to always
- # return true, and the tests would pass. It is up to you to ensure that
- # the values are semantically meaningful.
+ # returned values. For instance, you could implement <tt>valid?</tt> to
+ # always return true, and the tests would pass. It is up to you to ensure
+ # that the values are semantically meaningful.
#
- # Objects you pass in are expected to return a compliant object from a
- # call to to_model. It is perfectly fine for to_model to return self.
+ # Objects you pass in are expected to return a compliant object from a call
+ # to <tt>to_model</tt>. It is perfectly fine for <tt>to_model</tt> to return
+ # +self+.
module Tests
# == Responds to <tt>to_key</tt>
#
# Returns an Enumerable of all (primary) key attributes
- # or nil if model.persisted? is false. This is used by
- # dom_id to generate unique ids for the object.
+ # or nil if <tt>model.persisted?</tt> is false. This is used by
+ # <tt>dom_id</tt> to generate unique ids for the object.
def test_to_key
assert model.respond_to?(:to_key), "The model should respond to to_key"
def model.persisted?() false end
@@ -34,13 +35,14 @@ module ActiveModel
# == Responds to <tt>to_param</tt>
#
# Returns a string representing the object's key suitable for use in URLs
- # or nil if model.persisted? is false.
+ # or +nil+ if <tt>model.persisted?</tt> is +false+.
#
- # Implementers can decide to either raise an exception or provide a default
- # in case the record uses a composite primary key. There are no tests for this
- # behavior in lint because it doesn't make sense to force any of the possible
- # implementation strategies on the implementer. However, if the resource is
- # not persisted?, then to_param should always return nil.
+ # Implementers can decide to either raise an exception or provide a
+ # default in case the record uses a composite primary key. There are no
+ # tests for this behavior in lint because it doesn't make sense to force
+ # any of the possible implementation strategies on the implementer.
+ # However, if the resource is not persisted?, then <tt>to_param</tt>
+ # should always return +nil+.
def test_to_param
assert model.respond_to?(:to_param), "The model should respond to to_param"
def model.to_key() [1] end
@@ -50,9 +52,8 @@ module ActiveModel
# == Responds to <tt>to_partial_path</tt>
#
- # Returns a string giving a relative path. This is used for looking up
+ # Returns a string giving a relative path. This is used for looking up
# partials. For example, a BlogPost model might return "blog_posts/blog_post"
- #
def test_to_partial_path
assert model.respond_to?(:to_partial_path), "The model should respond to to_partial_path"
assert_kind_of String, model.to_partial_path
@@ -60,11 +61,11 @@ module ActiveModel
# == Responds to <tt>persisted?</tt>
#
- # Returns a boolean that specifies whether the object has been persisted yet.
- # This is used when calculating the URL for an object. If the object is
- # not persisted, a form for that object, for instance, will route to the
- # create action. If it is persisted, a form for the object will routes to
- # the update action.
+ # Returns a boolean that specifies whether the object has been persisted
+ # yet. This is used when calculating the URL for an object. If the object
+ # is not persisted, a form for that object, for instance, will route to
+ # the create action. If it is persisted, a form for the object will routes
+ # to the update action.
def test_persisted?
assert model.respond_to?(:persisted?), "The model should respond to persisted?"
assert_boolean model.persisted?, "persisted?"
@@ -73,8 +74,8 @@ module ActiveModel
# == Naming
#
# Model.model_name must return a string with some convenience methods:
- # :human, :singular, and :plural. Check ActiveModel::Naming for more information.
- #
+ # <tt>:human</tt>, <tt>:singular</tt> and <tt>:plural</tt>. Check
+ # ActiveModel::Naming for more information.
def test_model_naming
assert model.class.respond_to?(:model_name), "The model should respond to model_name"
model_name = model.class.model_name
diff --git a/activemodel/lib/active_model/model.rb b/activemodel/lib/active_model/model.rb
index cb0a051ca5..33a530e6bd 100644
--- a/activemodel/lib/active_model/model.rb
+++ b/activemodel/lib/active_model/model.rb
@@ -2,11 +2,11 @@ module ActiveModel
# == Active Model Basic Model
#
- # Includes the required interface for an object to interact with <tt>ActionPack</tt>,
- # using different <tt>ActiveModel</tt> modules. It includes model name introspections,
- # conversions, translations and validations. Besides that, it allows you to
- # initialize the object with a hash of attributes, pretty much like
- # <tt>ActiveRecord</tt> does.
+ # Includes the required interface for an object to interact with
+ # <tt>ActionPack</tt>, using different <tt>ActiveModel</tt> modules.
+ # It includes model name introspections, conversions, translations and
+ # validations. Besides that, it allows you to initialize the object with a
+ # hash of attributes, pretty much like <tt>ActiveRecord</tt> does.
#
# A minimal implementation could be:
#
@@ -15,13 +15,13 @@ module ActiveModel
# attr_accessor :name, :age
# end
#
- # person = Person.new(:name => 'bob', :age => '18')
+ # person = Person.new(name: 'bob', age: '18')
# person.name # => 'bob'
- # person.age # => 18
+ # person.age # => 18
#
- # Note that, by default, <tt>ActiveModel::Model</tt> implements <tt>persisted?</tt> to
- # return <tt>false</tt>, which is the most common case. You may want to override it
- # in your class to simulate a different scenario:
+ # Note that, by default, <tt>ActiveModel::Model</tt> implements <tt>persisted?</tt>
+ # to return +false+, which is the most common case. You may want to override
+ # it in your class to simulate a different scenario:
#
# class Person
# include ActiveModel::Model
@@ -32,11 +32,12 @@ module ActiveModel
# end
# end
#
- # person = Person.new(:id => 1, :name => 'bob')
+ # person = Person.new(id: 1, name: 'bob')
# person.persisted? # => true
#
- # Also, if for some reason you need to run code on <tt>initialize</tt>, make sure you
- # call super if you want the attributes hash initialization to happen.
+ # Also, if for some reason you need to run code on <tt>initialize</tt>, make
+ # sure you call +super+ if you want the attributes hash initialization to
+ # happen.
#
# class Person
# include ActiveModel::Model
@@ -48,11 +49,12 @@ module ActiveModel
# end
# end
#
- # person = Person.new(:id => 1, :name => 'bob')
+ # person = Person.new(id: 1, name: 'bob')
# person.omg # => true
#
- # For more detailed information on other functionalities available, please refer
- # to the specific modules included in <tt>ActiveModel::Model</tt> (see below).
+ # For more detailed information on other functionalities available, please
+ # refer to the specific modules included in <tt>ActiveModel::Model</tt>
+ # (see below).
module Model
def self.included(base) #:nodoc:
base.class_eval do
@@ -63,12 +65,31 @@ module ActiveModel
end
end
+ # Initializes a new model with the given +params+.
+ #
+ # class Person
+ # include ActiveModel::Model
+ # attr_accessor :name, :age
+ # end
+ #
+ # person = Person.new(name: 'bob', age: '18')
+ # person.name # => "bob"
+ # person.age # => 18
def initialize(params={})
params.each do |attr, value|
self.public_send("#{attr}=", value)
end if params
end
+ # Indicates if the model is persisted. Default is +false+.
+ #
+ # class Person
+ # include ActiveModel::Model
+ # attr_accessor :id, :name
+ # end
+ #
+ # person = Person.new(id: 1, name: 'bob')
+ # person.persisted? # => false
def persisted?
false
end
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index 2b5fc57a3a..ea4f9341c6 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -14,9 +14,137 @@ module ActiveModel
alias_method :cache_key, :collection
+ ##
+ # :method: ==
+ #
+ # :call-seq:
+ # ==(other)
+ #
+ # Equivalent to <tt>String#==</tt>. Returns +true+ if the class name and
+ # +other+ are equal, otherwise +false+.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
+ #
+ # BlogPost.model_name == 'BlogPost' # => true
+ # BlogPost.model_name == 'Blog Post' # => false
+
+ ##
+ # :method: ===
+ #
+ # :call-seq:
+ # ===(other)
+ #
+ # Equivalent to <tt>#==</tt>.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
+ #
+ # BlogPost.model_name === 'BlogPost' # => true
+ # BlogPost.model_name === 'Blog Post' # => false
+
+ ##
+ # :method: <=>
+ #
+ # :call-seq:
+ # ==(other)
+ #
+ # Equivalent to <tt>String#<=></tt>.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
+ #
+ # BlogPost.model_name <=> 'BlogPost' # => 0
+ # BlogPost.model_name <=> 'Blog' # => 1
+ # BlogPost.model_name <=> 'BlogPosts' # => -1
+
+ ##
+ # :method: =~
+ #
+ # :call-seq:
+ # =~(regexp)
+ #
+ # Equivalent to <tt>String#=~</tt>. Match the class name against the given
+ # regexp. Returns the position where the match starts or +nil+ if there is
+ # no match.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
+ #
+ # BlogPost.model_name =~ /Post/ # => 4
+ # BlogPost.model_name =~ /\d/ # => nil
+
+ ##
+ # :method: !~
+ #
+ # :call-seq:
+ # !~(regexp)
+ #
+ # Equivalent to <tt>String#!~</tt>. Match the class name against the given
+ # regexp. Returns +true+ if there is no match, otherwise +false+.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
+ #
+ # BlogPost.model_name !~ /Post/ # => false
+ # BlogPost.model_name !~ /\d/ # => true
+
+ ##
+ # :method: eql?
+ #
+ # :call-seq:
+ # eql?(other)
+ #
+ # Equivalent to <tt>String#eql?</tt>. Returns +true+ if the class name and
+ # +other+ have the same length and content, otherwise +false+.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
+ #
+ # BlogPost.model_name.eql?('BlogPost') # => true
+ # BlogPost.model_name.eql?('Blog Post') # => false
+
+ ##
+ # :method: to_s
+ #
+ # :call-seq:
+ # to_s()
+ #
+ # Returns the class name.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
+ #
+ # BlogPost.model_name.to_s # => "BlogPost"
+
+ ##
+ # :method: to_str
+ #
+ # :call-seq:
+ # to_str()
+ #
+ # Equivalent to +to_s+.
delegate :==, :===, :<=>, :=~, :"!~", :eql?, :to_s,
:to_str, :to => :name
+ # Returns a new ActiveModel::Name instance. By default, the +namespace+
+ # and +name+ option will take the namespace and name of the given class
+ # respectively.
+ #
+ # module Foo
+ # class Bar
+ # end
+ # end
+ #
+ # ActiveModel::Name.new(Foo::Bar).to_s
+ # # => "Foo::Bar"
def initialize(klass, namespace = nil, name = nil)
@name = name || klass.name
@@ -38,7 +166,11 @@ module ActiveModel
end
# Transform the model name into a more humane format, using I18n. By default,
- # it will underscore then humanize the class name
+ # it will underscore then humanize the class name.
+ #
+ # class BlogPost
+ # extend ActiveModel::Naming
+ # end
#
# BlogPost.model_name.human # => "Blog post"
#
@@ -82,11 +214,12 @@ module ActiveModel
# BookModule::BookCover.model_name.i18n_key # => :"book_module/book_cover"
#
# Providing the functionality that ActiveModel::Naming provides in your object
- # is required to pass the Active Model Lint test. So either extending the provided
- # method below, or rolling your own is required.
+ # is required to pass the Active Model Lint test. So either extending the
+ # provided method below, or rolling your own is required.
module Naming
# Returns an ActiveModel::Name object for module. It can be
- # used to retrieve all kinds of naming-related information.
+ # used to retrieve all kinds of naming-related information
+ # (See ActiveModel::Name for more information).
def model_name
@_model_name ||= begin
namespace = self.parents.detect do |n|
@@ -96,7 +229,7 @@ module ActiveModel
end
end
- # Returns the plural class name of a record or class. Examples:
+ # Returns the plural class name of a record or class.
#
# ActiveModel::Naming.plural(post) # => "posts"
# ActiveModel::Naming.plural(Highrise::Person) # => "highrise_people"
@@ -104,7 +237,7 @@ module ActiveModel
model_name_from_record_or_class(record_or_class).plural
end
- # Returns the singular class name of a record or class. Examples:
+ # Returns the singular class name of a record or class.
#
# ActiveModel::Naming.singular(post) # => "post"
# ActiveModel::Naming.singular(Highrise::Person) # => "highrise_person"
@@ -112,10 +245,10 @@ module ActiveModel
model_name_from_record_or_class(record_or_class).singular
end
- # Identifies whether the class name of a record or class is uncountable. Examples:
+ # Identifies whether the class name of a record or class is uncountable.
#
# ActiveModel::Naming.uncountable?(Sheep) # => true
- # ActiveModel::Naming.uncountable?(Post) => false
+ # ActiveModel::Naming.uncountable?(Post) # => false
def self.uncountable?(record_or_class)
plural(record_or_class) == singular(record_or_class)
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 68f8bbeb1c..a62fce4756 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1167,6 +1167,8 @@ module ActiveRecord
# If true, always save the associated objects or destroy them if marked for destruction,
# when saving the parent object. If false, never save or destroy the associated objects.
# By default, only save associated objects that are new records.
+ #
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
# [:inverse_of]
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
# that is the inverse of this <tt>has_many</tt> association. Does not work in combination
@@ -1288,6 +1290,8 @@ module ActiveRecord
# If true, always save the associated object or destroy it if marked for destruction,
# when saving the parent object. If false, never save or destroy the associated object.
# By default, only save the associated object if it's a new record.
+ #
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
# [:inverse_of]
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
# that is the inverse of this <tt>has_one</tt> association. Does not work in combination
@@ -1404,6 +1408,8 @@ module ActiveRecord
# saving the parent object.
# If false, never save or destroy the associated object.
# By default, only save the associated object if it's a new record.
+ #
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
# [:touch]
# If true, the associated object will be touched (the updated_at/on attributes set to now)
# when this record is either saved or destroyed. If you specify a symbol, that attribute
@@ -1589,6 +1595,8 @@ module ActiveRecord
# If false, never save or destroy the associated objects.
# By default, only save associated objects that are new records.
#
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
+ #
# Option examples:
# has_and_belongs_to_many :projects
# has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index e6a67b76fe..974cd326ef 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -146,8 +146,8 @@ module ActiveRecord
to_a
end
- # Returns true if a record exists in the table that matches the +id+ or
- # conditions given, or false otherwise. The argument can take five forms:
+ # Returns +true+ if a record exists in the table that matches the +id+ or
+ # conditions given, or +false+ otherwise. The argument can take six forms:
#
# * Integer - Finds the record with this primary key.
# * String - Finds the record with a primary key corresponding to this
@@ -155,8 +155,9 @@ module ActiveRecord
# * Array - Finds the record that matches these +find+-style conditions
# (such as <tt>['color = ?', 'red']</tt>).
# * Hash - Finds the record that matches these +find+-style conditions
- # (such as <tt>{:color => 'red'}</tt>).
- # * No args - Returns false if the table is empty, true otherwise.
+ # (such as <tt>{color: 'red'}</tt>).
+ # * +false+ - Returns always +false+.
+ # * No args - Returns +false+ if the table is empty, +true+ otherwise.
#
# For more information about specifying conditions as a Hash or Array,
# see the Conditions section in the introduction to ActiveRecord::Base.
@@ -168,7 +169,8 @@ module ActiveRecord
# Person.exists?(5)
# Person.exists?('5')
# Person.exists?(['name LIKE ?', "%#{query}%"])
- # Person.exists?(:name => "David")
+ # Person.exists?(name: 'David')
+ # Person.exists?(false)
# Person.exists?
def exists?(conditions = :none)
conditions = conditions.id if ActiveRecord::Model === conditions
diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb
index 5a61906222..c82da3c6c2 100644
--- a/activesupport/lib/active_support/core_ext/hash/except.rb
+++ b/activesupport/lib/active_support/core_ext/hash/except.rb
@@ -4,13 +4,6 @@ class Hash
#
# @person.update_attributes(params[:person].except(:admin))
#
- # If the receiver responds to +convert_key+, the method is called on each of the
- # arguments. This allows +except+ to play nice with hashes with indifferent access
- # for instance:
- #
- # {:a => 1}.with_indifferent_access.except(:a) # => {}
- # {:a => 1}.with_indifferent_access.except('a') # => {}
- #
def except(*keys)
dup.except!(*keys)
end
diff --git a/guides/source/debugging_rails_applications.textile b/guides/source/debugging_rails_applications.textile
index 0802a2db26..cc172042e9 100644
--- a/guides/source/debugging_rails_applications.textile
+++ b/guides/source/debugging_rails_applications.textile
@@ -102,7 +102,7 @@ It can also be useful to save information to log files at runtime. Rails maintai
h4. What is the Logger?
-Rails makes use of Ruby's standard +logger+ to write log information. You can also substitute another logger such as +Log4r+ if you wish.
+Rails makes use of the +ActiveSupport::BufferedLogger+ class to write log information. You can also substitute another logger such as +Log4r+ if you wish.
You can specify an alternative logger in your +environment.rb+ or any environment file:
diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile
index 897327a888..07419d11b4 100644
--- a/guides/source/getting_started.textile
+++ b/guides/source/getting_started.textile
@@ -900,7 +900,7 @@ end
</ruby>
The new method, +update_attributes+, is used when you want to update a record
-that already exists, and it accepts an hash containing the attributes
+that already exists, and it accepts a hash containing the attributes
that you want to update. As before, if there was an error updating the
post we want to show the form back to the user.
@@ -1185,7 +1185,7 @@ delete "posts/:id" => "posts#destroy"
That's a lot to type for covering a single *resource*. Fortunately,
Rails provides a +resources+ method which can be used to declare a
-standard REST resource. Here's how +config/routes/rb+ looks after the
+standard REST resource. Here's how +config/routes.rb+ looks after the
cleanup:
<ruby>
diff --git a/guides/source/performance_testing.textile b/guides/source/performance_testing.textile
index 958b13cd9e..982fd1b070 100644
--- a/guides/source/performance_testing.textile
+++ b/guides/source/performance_testing.textile
@@ -524,11 +524,11 @@ Please refer to the "API docs":http://api.rubyonrails.org/classes/ActiveRecord/B
h4. Controller
-Similarly, you could use this helper method inside "controllers":http://api.rubyonrails.org/classes/ActionController/Benchmarking/ClassMethods.html#M000715
+Similarly, you could use this helper method inside "controllers":http://api.rubyonrails.org/classes/ActiveSupport/Benchmarkable.html
<ruby>
def process_projects
- self.class.benchmark("Processing projects") do
+ benchmark("Processing projects") do
Project.process(params[:project_ids])
Project.update_cached_projects
end
@@ -539,7 +539,7 @@ NOTE: +benchmark+ is a class method inside controllers
h4. View
-And in "views":http://api.rubyonrails.org/classes/ActionController/Benchmarking/ClassMethods.html#M000715:
+And in "views":http://api.rubyonrails.org/classes/ActiveSupport/Benchmarkable.html:
<erb>
<% benchmark("Showing projects partial") do %>
diff --git a/guides/source/routing.textile b/guides/source/routing.textile
index 4de76ff100..cffbf9bec4 100644
--- a/guides/source/routing.textile
+++ b/guides/source/routing.textile
@@ -32,7 +32,13 @@ the request is dispatched to the +patients+ controller's +show+ action with <tt>
h4. Generating Paths and URLs from Code
-You can also generate paths and URLs. If your application contains this code:
+You can also generate paths and URLs. If the route above is modified to be
+
+<ruby>
+get "/patients/:id" => "patients#show", :as => "patient"
+</ruby>
+
+If your application contains this code:
<ruby>
@patient = Patient.find(17)