Permalink
Browse files

Merge branch 'master' of github.com:lifo/docrails

  • Loading branch information...
2 parents c178a26 + 873c5a9 commit 2b2ee222f3012a29c9db95d357a30029100b226b @paulccarey paulccarey committed Jul 29, 2010
@@ -74,9 +74,9 @@ Or you can just chain the methods together like:
== Receiving emails
-To receive emails, you need to implement a public instance method called receive that takes a
+To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes a
tmail object as its single parameter. The Action Mailer framework has a corresponding class method,
-which is also called receive, that accepts a raw, unprocessed email as a string, which it then turns
+which is also called <tt>receive</tt>, that accepts a raw, unprocessed email as a string, which it then turns
into the tmail object and calls the receive instance method.
Example:
@@ -41,16 +41,16 @@ module ActionMailer #:nodoc:
# in the same manner as <tt>attachments[]=</tt>
#
# * <tt>headers[]=</tt> - Allows you to specify any header field in your email such
- # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note, while most fields (like <tt>To:</tt>
+ # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note, while most fields like <tt>To:</tt>
# <tt>From:</tt> can only appear once in an email header, other fields like <tt>X-Anything</tt>
# can appear multiple times. If you want to change a field that can appear multiple times,
- # you need to set it to nil first so that Mail knows you are replacing it, not adding
- # another field of the same name.)
+ # you need to set it to nil first so that Mail knows you are replacing it and not adding
+ # another field of the same name.
#
# * <tt>headers(hash)</tt> - Allows you to specify multiple headers in your email such
# as <tt>headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'})</tt>
#
- # * <tt>mail</tt> - Allows you to specify your email to send.
+ # * <tt>mail</tt> - Allows you to specify email to be sent.
#
# The hash passed to the mail method allows you to specify any header that a Mail::Message
# will accept (any valid Email header including optional fields).
@@ -66,7 +66,7 @@ module ActionMailer #:nodoc:
# format.html
# end
#
- # The block syntax is useful if also need to specify information specific to a part:
+ # The block syntax is also useful in providing information specific to a part:
#
# mail(:to => user.email) do |format|
# format.text(:content_transfer_encoding => "base64")
@@ -121,7 +121,7 @@ module ActionMailer #:nodoc:
#
# <%= users_url(:host => "example.com") %>
#
- # You will want to avoid using the <tt>name_of_route_path</tt> form of named routes because it doesn't
+ # You want to avoid using the <tt>name_of_route_path</tt> form of named routes because it doesn't
# make sense to generate relative URLs in email messages.
#
# It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt>
@@ -132,7 +132,7 @@ module ActionMailer #:nodoc:
# Setting <tt>ActionMailer::Base.default_url_options</tt> directly is now deprecated, use the configuration
# option mentioned above to set the default host.
#
- # If you do decide to set a default <tt>:host</tt> for your mailers you will want to use the
+ # If you do decide to set a default <tt>:host</tt> for your mailers you want to use the
# <tt>:only_path => false</tt> option when using <tt>url_for</tt>. This will ensure that absolute URLs are
# generated because the <tt>url_for</tt> view helper will, by default, generate relative URLs when a
# <tt>:host</tt> option isn't explicitly provided.
@@ -154,7 +154,7 @@ module ActionMailer #:nodoc:
# detect and use multipart templates, where each template is named after the name of the action, followed
# by the content type. Each such detected template will be added as separate part to the message.
#
- # For example, if the following templates existed:
+ # For example, if the following templates exist:
# * signup_notification.text.plain.erb
# * signup_notification.text.html.erb
# * signup_notification.text.xml.builder
@@ -171,8 +171,7 @@ module ActionMailer #:nodoc:
#
# = Attachments
#
- # You can see above how to make a multipart HTML / Text email, to send attachments is just
- # as easy:
+ # Sending attachment in emails is easy:
#
# class ApplicationMailer < ActionMailer::Base
# def welcome(recipient)
@@ -189,10 +188,8 @@ module ActionMailer #:nodoc:
#
# = Inline Attachments
#
- # You can also specify that a file should be displayed inline with other HTML. For example a
- # corporate logo or a photo or the like.
- #
- # To do this is simple, in the Mailer:
+ # You can also specify that a file should be displayed inline with other HTML. This is useful
+ # if you want to display a corporate logo or a photo.
#
# class ApplicationMailer < ActionMailer::Base
# def welcome(recipient)
@@ -83,7 +83,10 @@ module ActiveModel
# person.name_changed? # => false
# person.name # => 'Bill'
#
- # Before modifying an attribute in-place:
+ # 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.
+ #
# person.name_will_change!
# person.name << 'y'
# person.name_change # => ['Bill', 'Billy']
@@ -303,7 +303,7 @@ def association_instance_set(name, association)
# You can manipulate objects and associations before they are saved to the database, but there is some special behavior you should be
# aware of, mostly involving the saving of associated objects.
#
- # Unless you set the :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
+ # You can set the :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
# <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association. Setting it
# to +true+ will _always_ save the members, whereas setting it to +false+ will
# _never_ save the members.
@@ -220,6 +220,19 @@ module ActiveRecord #:nodoc:
# user = User.create(:preferences => %w( one two three ))
# User.find(user.id).preferences # raises SerializationTypeMismatch
#
+ # == Time Zone aware attributes
+ #
+ # By default, ActiveRecord::Base keeps all the datetime columns time zone aware by executing following code.
+ #
+ # ActiveRecord::Base.time_zone_aware_attributes = true
+ #
+ # This feature can easily be turned off by assigning value <tt>false</tt> .
+ #
+ # If your attributes are time zone aware and you desire to skip time zone conversion for certain attributes then you can do following:
+ #
+ # Topic.skip_time_zone_conversion_for_attributes = [:written_on]
+ #
+ #
# == Single table inheritance
#
# Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed
@@ -105,11 +105,16 @@ def becomes(klass)
# Updates a single attribute and saves the record.
# This is especially useful for boolean flags on existing records. Also note that
#
- # * validation is skipped
- # * No callbacks are invoked
- # * updated_at/updated_on column is updated if that column is available
- # * does not work on associations
- # * does not work on attr_accessor attributes. The attribute that is being updated must be column name.
+ # * The attribute being updated must be a column name.
+ # * Validation is skipped.
+ # * No callbacks are invoked.
+ # * updated_at/updated_on column is updated if that column is available.
+ # * Does not work on associations.
+ # * Does not work on attr_accessor attributes.
+ # * Does not work on new record. <tt>record.new_record?</tt> should return false for this method to work.
+ # * Updates only the attribute that is input to the method. If there are other changed attributes then
+ # those attributes are left alone. In that case even after this method has done its work <tt>record.changed?</tt>
+ # will return true.
#
def update_attribute(name, value)
raise ActiveRecordError, "#{name.to_s} is marked as readonly" if self.class.readonly_attributes.include? name.to_s
@@ -129,13 +129,6 @@ def self.expand_cache_key(key, namespace = nil)
# cache.namespace = lambda { @last_mod_time } # Set the namespace to a variable
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
#
- # All caches support auto expiring content after a specified number of seconds.
- # To set the cache entry time to live, you can either specify +:expires_in+ as
- # an option to the constructor to have it affect all entries or to the +fetch+
- # or +write+ methods for just one entry.
- #
- # cache = ActiveSupport::Cache::MemoryStore.new(:expire_in => 5.minutes)
- # cache.write(key, value, :expire_in => 1.minute) # Set a lower value for one entry
#
# Caches can also store values in a compressed format to save space and reduce
# time spent sending data. Since there is some overhead, values must be large
@@ -211,23 +204,30 @@ def self.instrument
# Setting <tt>:compress</tt> will store a large cache entry set by the call
# in a compressed format.
#
- # Setting <tt>:expires_in</tt> will set an expiration time on the cache
- # entry if it is set by call.
#
- # Setting <tt>:race_condition_ttl</tt> will invoke logic on entries set with
- # an <tt>:expires_in</tt> option. If an entry is found in the cache that is
- # expired and it has been expired for less than the number of seconds specified
- # by this option and a block was passed to the method call, then the expiration
- # future time of the entry in the cache will be updated to that many seconds
- # in the and the block will be evaluated and written to the cache.
+ # Setting <tt>:expires_in</tt> will set an expiration time on the cache. All caches
+ # support auto expiring content after a specified number of seconds. This value can
+ # be specified as an option to the construction in which call all entries will be
+ # affected. Or it can be supplied to the +fetch+ or +write+ method for just one entry.
+ #
+ # cache = ActiveSupport::Cache::MemoryStore.new(:expire_in => 5.minutes)
+ # cache.write(key, value, :expire_in => 1.minute) # Set a lower value for one entry
+ #
+ # Setting <tt>:race_condition_ttl</tt> is very useful in situations where a cache entry
+ # is used very frequently unver heavy load. If a cache expires and due to heavy load
+ # seven different processes will try to read data natively and then they all will try to
+ # write to cache. To avoid that case the first process to find an expired cache entry will
+ # bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>. Yes
+ # this process is extending the time for a stale value by another few seconds. Because
+ # of extended life of the previous cache, other processes will continue to use slightly
+ # stale data for a just a big longer. In the meantime that first process will go ahead
+ # and will write into cache the new value. After that all the processes will start
+ # getting new value. The key is to keep <tt>:race_condition_ttl</tt> small.
#
- # This is very useful in situations where a cache entry is used very frequently
- # under heavy load. The first process to find an expired cache entry will then
- # become responsible for regenerating that entry while other processes continue
- # to use the slightly out of date entry. This can prevent race conditions where
- # too many processes are trying to regenerate the entry all at once. If the
- # process regenerating the entry errors out, the entry will be regenerated
- # after the specified number of seconds.
+ # If the process regenerating the entry errors out, the entry will be regenerated
+ # after the specified number of seconds. Also note that the life of stale cache is
+ # extended only if it expired recently. Otherwise a new value is generated and
+ # <tt>:race_condition_ttl</tt> does not play any role.
#
# # Set all values to expire after one minute.
# cache = ActiveSupport::Cache::MemoryCache.new(:expires_in => 1.minute)
@@ -252,6 +252,7 @@ def self.instrument
#
# # val_1 => "new value 1"
# # val_2 => "original value"
+ # # sleep 10 # First thread extend the life of cache by another 10 seconds
# # cache.fetch("foo") => "new value 1"
#
# Other options will be handled by the specific cache store implementation.
@@ -2,8 +2,8 @@
require 'active_support/core_ext/module/remove_method'
class Class
- # Declare a class-level attribute whose value is inheritable and
- # overwritable by subclasses:
+ # Declare a class-level attribute whose value is inheritable by subclasses.
+ # Subclasses can change their own value and it will not impact parent class.
#
# class Base
# class_attribute :setting
@@ -18,12 +18,34 @@ class Class
# Subclass.setting # => false
# Base.setting # => true
#
+ # In the above case as long as Subclass does not assign a value to setting
+ # by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt>
+ # would read value assigned to parent class. Once Subclass assigns a value then
+ # the value assigned by Subclass would be returned.
+ #
# This matches normal Ruby method inheritance: think of writing an attribute
- # on a subclass as overriding the reader method.
+ # on a subclass as overriding the reader method. However, you need to be aware
+ # when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
+ # In such cases, you don't want to do changes in places but use setters:
+ #
+ # Base.setting = []
+ # Base.setting #=> []
+ # Subclass.setting #=> []
+ #
+ # # Appending in child changes both parent and child because it is the same object:
+ # Subclass.setting << :foo
+ # Base.setting #=> [:foo]
+ # Subclass.setting #=> [:foo]
+ #
+ # # Use setters to not propagate changes:
+ # Base.setting = []
+ # Subclass.setting += [:foo]
+ # Base.setting #=> []
+ # Subclass.setting #=> [:foo]
#
# For convenience, a query method is defined as well:
#
- # Subclass.setting? # => false
+ # Subclass.setting? # => false
#
# Instances may overwrite the class value in the same way:
#
@@ -3,11 +3,27 @@
# Extends the class object with class and instance accessors for class attributes,
# just like the native attr* accessors for instance attributes.
#
+# Note that unlike +class_attribute+, if a subclass changes the value then that would
+# also change the value for parent class. Similarly if parent class changes the value
+# then that would change the value of subclasses too.
+#
# class Person
# cattr_accessor :hair_colors
# end
#
# Person.hair_colors = [:brown, :black, :blonde, :red]
+# Person.hair_colors #=> [:brown, :black, :blonde, :red]
+# Person.new.hair_colors #=> [:brown, :black, :blonde, :red]
+#
+# To opt out of the instance writer method, pass :instance_writer => false.
+# To opt out of the instance reader method, pass :instance_reader => false.
+#
+# class Person
+# cattr_accessor :hair_colors, :instance_writer => false, :instance_reader => false
+# end
+#
+# Person.new.hair_colors = [:brown] # => NoMethodError
+# Person.new.hair_colors # => NoMethodError
class Class
def cattr_reader(*syms)
options = syms.extract_options!
@@ -40,23 +40,23 @@ def current
end
end
- # Tells whether the Date object's date lies in the past
+ # Returns true if the Date object's date lies in the past. Otherwise returns false.
def past?
self < ::Date.current
end
- # Tells whether the Date object's date is today
+ # Returns true if the Date object's date is today.
def today?
self.to_date == ::Date.current # we need the to_date because of DateTime
end
- # Tells whether the Date object's date lies in the future
+ # Returns true if the Date object's date lies in the future.
def future?
self > ::Date.current
end
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
- # and then subtracts the specified number of seconds
+ # and then subtracts the specified number of seconds.
def ago(seconds)
to_time_in_current_zone.since(-seconds)
end
@@ -127,22 +127,22 @@ def change(options)
)
end
- # Returns a new Date/DateTime representing the time a number of specified months ago
+ # Returns a new Date/DateTime representing the time a number of specified months ago.
def months_ago(months)
advance(:months => -months)
end
- # Returns a new Date/DateTime representing the time a number of specified months in the future
+ # Returns a new Date/DateTime representing the time a number of specified months in the future.
def months_since(months)
advance(:months => months)
end
- # Returns a new Date/DateTime representing the time a number of specified years ago
+ # Returns a new Date/DateTime representing the time a number of specified years ago.
def years_ago(years)
advance(:years => -years)
end
- # Returns a new Date/DateTime representing the time a number of specified years in the future
+ # Returns a new Date/DateTime representing the time a number of specified years in the future.
def years_since(years)
advance(:years => years)
end
@@ -152,22 +152,22 @@ def prev_year
years_ago(1)
end unless method_defined?(:prev_year)
- # Short-hand for years_since(1)
+ # Shorthand for years_since(1)
def next_year
years_since(1)
end unless method_defined?(:next_year)
- # Short-hand for months_ago(1)
+ # Shorthand for months_ago(1)
def prev_month
months_ago(1)
end unless method_defined?(:prev_month)
- # Short-hand for months_since(1)
+ # Shorthand for months_since(1)
def next_month
months_since(1)
end unless method_defined?(:next_month)
- # Returns a new Date/DateTime representing the "start" of this week (i.e, Monday; DateTime objects will have time set to 0:00)
+ # Returns a new Date/DateTime representing the "start" of this week (i.e, Monday; DateTime objects will have time set to 0:00).
def beginning_of_week
days_to_monday = self.wday!=0 ? self.wday-1 : 6
result = self - days_to_monday
@@ -176,7 +176,7 @@ def beginning_of_week
alias :monday :beginning_of_week
alias :at_beginning_of_week :beginning_of_week
- # Returns a new Date/DateTime representing the end of this week (Sunday, DateTime objects will have time set to 23:59:59)
+ # Returns a new Date/DateTime representing the end of this week (Sunday, DateTime objects will have time set to 23:59:59).
def end_of_week
days_to_sunday = self.wday!=0 ? 7-self.wday : 0
result = self + days_to_sunday.days
Oops, something went wrong.

0 comments on commit 2b2ee22

Please sign in to comment.