Permalink
Browse files

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

Conflicts:
	activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  • Loading branch information...
2 parents 6107407 + 2db79dc commit cb524dc1d7525a26ecea8cf049757e530f0d4026 @vijaydev vijaydev committed Sep 9, 2012
@@ -1,6 +1,6 @@
module ActionController #:nodoc:
module Caching
- # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change.
+ # Sweepers are the terminators of the caching world and responsible for expiring caches when Active Record objects change.
# They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:
#
# class ListSweeper < ActionController::Caching::Sweeper
@@ -94,10 +94,10 @@ module ClassMethods
# validates :token, uniqueness: true, strict: TokenGenerationException
#
#
- # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+
- # and +:strict+ can be given to one specific validator, as a hash:
+ # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+, +:strict+
+ # and +:message+ can be given to one specific validator, as a hash:
#
- # validates :password, presence: { if: :password_required? }, confirmation: true
+ # validates :password, presence: { if: :password_required?, message: 'is forgotten.' }, confirmation: true
def validates(*attributes)
defaults = attributes.extract_options!.dup
validations = defaults.slice!(*_validates_default_keys)
@@ -494,7 +494,7 @@ def checkout_and_verify(c)
#
# Normally there is only a single ConnectionHandler instance, accessible via
# ActiveRecord::Base.connection_handler. Active Record models use this to
- # determine that connection pool that they should use.
+ # determine the connection pool that they should use.
class ConnectionHandler
def initialize
@owner_to_pool = Hash.new { |h,k| h[k] = {} }
@@ -82,7 +82,7 @@ def initialize_store_attribute(store_attribute)
attribute
end
- class IndifferentCoder
+ class IndifferentCoder # :nodoc:
def initialize(coder_or_class_name)
@coder =
if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
@@ -116,6 +116,20 @@ h3. Action Mailer
* Asynchronously send messages via the Rails Queue.
+* Delivery Options (such as SMTP Settings) can now be set dynamically per mailer action.
+
+Delivery options are set via <tt>:delivery_method_options</tt> key on mail.
+
+<ruby>
+def welcome_mailer(user,company)
+ mail to: user.email,
+ subject: "Welcome!",
+ delivery_method_options: {user_name: company.smtp_user,
+ password: company.smtp_password,
+ address: company.smtp_server}
+end
+</ruby>
+
h3. Action Pack
h4. Action Controller
@@ -410,6 +410,21 @@ end
The above will send a multipart email with an attachment, properly nested with the top level being <tt>multipart/mixed</tt> and the first part being a <tt>multipart/alternative</tt> containing the plain text and HTML email messages.
+h5. Sending Emails with Dynamic Delivery Options
+
+If you wish to override the default delivery options (e.g. SMTP credentials) while delivering emails, you can do this using +delivery_method_options+ in the mailer action.
+
+<ruby>
+class UserMailer < ActionMailer::Base
+ def welcome_email(user,company)
+ @user = user
+ @url = user_url(@user)
+ delivery_options = { user_name: company.smtp_user, password: company.smtp_password, address: company.smtp_host }
+ mail(to: user.email, subject: "Please see the Terms and Conditions attached", delivery_method_options: delivery_options)
+ end
+end
+</ruby>
+
h3. Receiving Emails
Receiving and parsing emails with Action Mailer can be a rather complex endeavor. Before your email reaches your Rails app, you would have had to configure your system to somehow forward emails to your app, which needs to be listening for that. So, to receive emails in your Rails app you'll need to:
@@ -1211,7 +1211,7 @@ Sample usage (selecting the associated Authors for an instance of Post, +@post+)
collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial)
</ruby>
-If <tt>@post.author_ids</tt> is [1], this would return:
+If <tt>@post.author_ids</tt> is <tt><notextile>[1]</notextile></tt>, this would return:
<html>
<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" />
@@ -266,7 +266,7 @@ SELECT * FROM clients WHERE (clients.id IN (1,10))
WARNING: <tt>Model.find(array_of_primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception unless a matching record is found for <strong>all</strong> of the supplied primary keys.
-h5. take
+h5(#take-n-objects). take
<tt>Model.take(limit)</tt> retrieves the first number of records specified by +limit+ without any explicit ordering:
@@ -282,7 +282,7 @@ The SQL equivalent of the above is:
SELECT * FROM clients LIMIT 2
</sql>
-h5. first
+h5(#first-n-objects). first
<tt>Model.first(limit)</tt> finds the first number of records specified by +limit+ ordered by primary key:
@@ -298,7 +298,7 @@ The SQL equivalent of the above is:
SELECT * FROM clients LIMIT 2
</sql>
-h5. last
+h5(#last-n-objects). last
<tt>Model.last(limit)</tt> finds the number of records specified by +limit+ ordered by primary key in descending order:
@@ -1144,30 +1144,54 @@ category.posts.created_before(time)
h4. Applying a default scope
-If we wish for a scope to be applied across all queries to the model we can use the +default_scope+ method within the model itself.
+If we wish for a scope to be applied across all queries to the model we can use the
++default_scope+ method within the model itself.
<ruby>
class Client < ActiveRecord::Base
default_scope { where("removed_at IS NULL") }
end
</ruby>
-When queries are executed on this model, the SQL query will now look something like this:
+When queries are executed on this model, the SQL query will now look something like
+this:
<sql>
SELECT * FROM clients WHERE removed_at IS NULL
</sql>
+If you need to do more complex things with a default scope, you can alternatively
+define it as a class method:
+
+<ruby>
+class Client < ActiveRecord::Base
+ def self.default_scope
+ # Should return an ActiveRecord::Relation.
+ end
+end
+</ruby>
+
h4. Removing all scoping
-If we wish to remove scoping for any reason we can use the +unscoped+ method. This is especially useful if a +default_scope+ is specified in the model and should not be applied for this particular query.
+If we wish to remove scoping for any reason we can use the +unscoped+ method. This is
+especially useful if a +default_scope+ is specified in the model and should not be
+applied for this particular query.
<ruby>
Client.unscoped.all
</ruby>
This method removes all scoping and will do a normal query on the table.
+Note that chaining +unscoped+ with a +scope+ does not work. In these cases, it is
+recommended that you use the block form of +unscoped+:
+
+<ruby>
+Client.unscoped {
+ Client.created_before(Time.zome.now)
+}
+</ruby>
+
h3. Dynamic Finders
For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called +first_name+ on your +Client+ model for example, you get +find_by_first_name+ and +find_all_by_first_name+ for free from Active Record. If you have a +locked+ field on the +Client+ model, you also get +find_by_locked+ and +find_all_by_locked+ methods.
@@ -1218,7 +1242,7 @@ Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false)
This method still works, but it's encouraged to use +first_or_create+ because it's more explicit on which arguments are used to _find_ the record and which are used to _create_, resulting in less confusion overall.
-h4. +first_or_create!+
+h4(#first_or_create_bang). +first_or_create!+
You can also use +first_or_create!+ to raise an exception if the new record is invalid. Validations are not covered on this guide, but let's assume for a moment that you temporarily add
@@ -88,6 +88,8 @@ end
!images/belongs_to.png(belongs_to Association Diagram)!
+NOTE: +belongs_to+ associations _must_ use the singular term. If you used the pluralized form in the above example for the +customer+ association in the +Order+ model, you would be told that there was an "uninitialized constant Order::Customers". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too.
+
h4. The +has_one+ Association
A +has_one+ association also sets up a one-to-one connection with another model, but with somewhat different semantics (and consequences). This association indicates that each instance of a model contains or possesses one instance of another model. For example, if each supplier in your application has only one account, you'd declare the supplier model like this:
@@ -173,7 +173,9 @@ expire_fragment('all_available_products')
h4. Sweepers
-Cache sweeping is a mechanism which allows you to get around having a ton of +expire_{page,action,fragment}+ calls in your code. It does this by moving all the work required to expire cached content into an +ActionController::Caching::Sweeper+ subclass. This class is an observer and looks for changes to an object via callbacks, and when a change occurs it expires the caches associated with that object in an around or after filter.
+Cache sweeping is a mechanism which allows you to get around having a ton of +expire_{page,action,fragment}+ calls in your code. It does this by moving all the work required to expire cached content into an +ActionController::Caching::Sweeper+ subclass. This class is an observer and looks for changes to an Active Record object via callbacks, and when a change occurs it expires the caches associated with that object in an around or after filter.
+
+TIP: Sweepers rely on the use of Active Record and Active Record Observers. The object you are observing must be an Active Record model.
Continuing with our Product controller example, we could rewrite it with a sweeper like this:
@@ -353,7 +355,7 @@ Note that the cache will grow until the disk is full unless you periodically cle
h4. ActiveSupport::Cache::MemCacheStore
-This cache store uses Danga's +memcached+ server to provide a centralized cache for your application. Rails uses the bundled +memcache-client+ gem by default. This is currently the most popular cache store for production websites. It can be used to provide a single, shared cache cluster with very a high performance and redundancy.
+This cache store uses Danga's +memcached+ server to provide a centralized cache for your application. Rails uses the bundled +dalli+ gem by default. This is currently the most popular cache store for production websites. It can be used to provide a single, shared cache cluster with very a high performance and redundancy.
When initializing the cache, you need to specify the addresses for all memcached servers in your cluster. If none is specified, it will assume memcached is running on the local host on the default port, but this is not an ideal set up for larger sites.
@@ -439,7 +441,7 @@ class ProductsController < ApplicationController
# If the request is stale according to the given timestamp and etag value
# (i.e. it needs to be processed again) then execute this block
- if stale?(:last_modified => @product.updated_at.utc, :etag => @product)
+ if stale?(:last_modified => @product.updated_at.utc, :etag => @product.cache_key)
respond_to do |wants|
# ... normal response processing
end
@@ -453,6 +455,17 @@ class ProductsController < ApplicationController
end
</ruby>
+Instead of a options hash, you can also simply pass in a model, Rails will use the +updated_at+ and +cache_key+ methods for setting +last_modified+ and +etag+:
+
+<ruby>
+class ProductsController < ApplicationController
+ def show
+ @product = Product.find(params[:id])
+ respond_with(@product) if stale?(@product)
+ end
+end
+</ruby>
+
If you don't have any special response processing and are using the default rendering mechanism (i.e. you're not using respond_to or calling render yourself) then you’ve got an easy helper in fresh_when:
<ruby>
@@ -388,7 +388,7 @@ And can reference in the view with the following code:
<erb>
<%= render @post %>
-<erb>
+</erb>
The default setting is +true+, which uses the partial at +/admin/posts/_post.erb+. Setting the value to +false+ would render +/posts/_post.erb+, which is the same behavior as rendering from a non-namespaced controller such as +PostsController+.
@@ -191,6 +191,17 @@ Completed in 0.01224 (81 reqs/sec) | DB: 0.00044 (3%) | 302 Found [http://localh
Adding extra logging like this makes it easy to search for unexpected or unusual behavior in your logs. If you add extra logging, be sure to make sensible use of log levels, to avoid filling your production logs with useless trivia.
+h4. Tagged Logging
+
+When running multi-user, multi-account applications, it’s often useful to be able to filter the logs using some custom rules. +TaggedLogging+ in Active Support helps in doing exactly that by stamping log lines with subdomains, request ids, and anything else to aid debugging such applications.
+
+<ruby>
+logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
+logger.tagged("BCX") { logger.info "Stuff" } # Logs "[BCX] Stuff"
+logger.tagged("BCX", "Jason") { logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff"
+logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff"
+</ruby>
+
h3. Debugging with the +debugger+ gem
When your code is behaving in unexpected ways, you can try printing to logs or the console to diagnose the problem. Unfortunately, there are times when this sort of error tracking is not effective in finding the root cause of a problem. When you actually need to journey into your running source code, the debugger is your best companion.
Oops, something went wrong.

0 comments on commit cb524dc

Please sign in to comment.