diff options
Diffstat (limited to 'railties/guides/source')
-rw-r--r-- | railties/guides/source/action_controller_overview.textile | 19 | ||||
-rw-r--r-- | railties/guides/source/action_mailer_basics.textile | 30 | ||||
-rw-r--r-- | railties/guides/source/active_record_querying.textile | 6 | ||||
-rw-r--r-- | railties/guides/source/association_basics.textile | 87 | ||||
-rw-r--r-- | railties/guides/source/caching_with_rails.textile | 13 | ||||
-rw-r--r-- | railties/guides/source/form_helpers.textile | 29 | ||||
-rw-r--r-- | railties/guides/source/layouts_and_rendering.textile | 65 | ||||
-rw-r--r-- | railties/guides/source/routing.textile | 38 |
8 files changed, 167 insertions, 120 deletions
diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index 5c77d74df1..c02e9f1912 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -98,7 +98,7 @@ The value of +params[:ids]+ will now be +["1", "2", "3"]+. Note that parameter v To send a hash you include the key name inside the brackets: <html> -<form action="/clients" method="post"> +<form accept-charset="UTF-8" action="/clients" method="post"> <input type="text" name="client[name]" value="Acme" /> <input type="text" name="client[phone]" value="12345" /> <input type="text" name="client[address][postcode]" value="12345" /> @@ -115,10 +115,7 @@ h4. Routing Parameters The +params+ hash will always contain the +:controller+ and +:action+ keys, but you should use the methods +controller_name+ and +action_name+ instead to access these values. Any other parameters defined by the routing, such as +:id+ will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the +:status+ parameter in a "pretty" URL: <ruby> -map.connect "/clients/:status", - :controller => "clients", - :action => "index", - :foo => "bar" +match '/clients/:status' => 'clients#index', :foo => "bar" </ruby> In this case, when a user opens the URL +/clients/active+, +params[:status]+ will be set to "active". When this route is used, +params[:foo]+ will also be set to "bar" just like it was passed in the query string. In the same way +params[:action]+ will contain "index". @@ -214,7 +211,7 @@ class ApplicationController < ActionController::Base # logging out removes it. def current_user @_current_user ||= session[:current_user_id] && - User.find(session[:current_user_id]) + User.find_by_id(session[:current_user_id]) end end </ruby> @@ -424,7 +421,7 @@ Around filters are responsible for running the action, but they can choose not t <ruby> # Example taken from the Rails API filter documentation: -# http://api.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html +# http://ap.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html class ApplicationController < ActionController::Base around_filter :catch_exceptions @@ -474,11 +471,11 @@ end Again, this is not an ideal example for this filter, because it's not run in the scope of the controller but gets the controller passed as an argument. The filter class has a class method +filter+ which gets run before or after the action, depending on if it's a before or after filter. Classes used as around filters can also use the same +filter+ method, which will get run in the same way. The method must +yield+ to execute the action. Alternatively, it can have both a +before+ and an +after+ method that are run before and after the action. -The Rails API documentation has "more information on using filters":http://api.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html. +The Rails API documentation has "more information on using filters":http://ap.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html. h3. Verification -Verifications make sure certain criteria are met in order for a controller or action to run. They can specify that a certain key (or several keys in the form of an array) is present in the +params+, +session+ or +flash+ hashes or that a certain HTTP method was used or that the request was made using +XMLHttpRequest+ (Ajax). The default action taken when these criteria are not met is to render a 400 Bad Request response, but you can customize this by specifying a redirect URL or rendering something else and you can also add flash messages and HTTP headers to the response. It is described in the "API documentation":http://api.rubyonrails.org/classes/ActionController/Verification/ClassMethods.html as "essentially a special kind of before_filter". +Verifications make sure certain criteria are met in order for a controller or action to run. They can specify that a certain key (or several keys in the form of an array) is present in the +params+, +session+ or +flash+ hashes or that a certain HTTP method was used or that the request was made using +XMLHttpRequest+ (Ajax). The default action taken when these criteria are not met is to render a 400 Bad Request response, but you can customize this by specifying a redirect URL or rendering something else and you can also add flash messages and HTTP headers to the response. It is described in the "API documentation":http://ap.rubyonrails.org/classes/ActionController/Verification/ClassMethods.html as "essentially a special kind of before_filter". Here's an example of using verification to make sure the user supplies a username and a password in order to log in: @@ -535,7 +532,7 @@ If you generate a form like this: You will see how the token gets added as a hidden field: <html> -<form action="/users/1" method="post"> +<form accept-charset="UTF-8" action="/users/1" method="post"> <input type="hidden" value="67250ab105eb5ad10851c00a5621854a23af5489" name="authenticity_token"/> @@ -555,7 +552,7 @@ In every controller there are two accessor methods pointing to the request and t h4. The +request+ Object -The request object contains a lot of useful information about the request coming in from the client. To get a full list of the available methods, refer to the "API documentation":http://api.rubyonrails.org/classes/ActionController/AbstractRequest.html. Among the properties that you can access on this object are: +The request object contains a lot of useful information about the request coming in from the client. To get a full list of the available methods, refer to the "API documentation":http://ap.rubyonrails.org/classes/ActionController/AbstractRequest.html. Among the properties that you can access on this object are: |_.Property of +request+|_.Purpose| |host|The hostname used for this request.| diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index 8eb48e2751..ac9052786e 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -242,6 +242,36 @@ end :class => 'photos' %> </erb> +h5. Sending Email To Multiple Recipients + +It is possible to send email to one or more recipients in one email (for e.g. informing all admins of a new signup) by setting the list of emails to the <tt>:to</tt> key. The <tt>to:</tt> key however expects a string so you have join the list of recipients using a comma. + +<ruby> + Class AdminMailer < ActionMailer::Base + default :to => Admin.all.map(&:email).join(", "), + :from => "notification@example.com" + + def new_registration(user) + @user = user + mail(:subject => "New User Signup: #{@user.email}") + end + end +</ruby> + +h5. Sending Email With Name + +Sometimes you wish to show the name of the person instead of just their email address when they receive the email. The trick to doing that is +to format the email address in the format <tt>"Name <email>"</tt>. + +<ruby> + def welcome_email(user) + @user = user + email_with_name = "#{@user.name} <#{@user.email}>" + mail(:to => email_with_name, + :subject => "Welcome to My Awesome Site") + end +</ruby> + h4. Mailer Views Mailer views are located in the +app/views/name_of_mailer_class+ directory. The specific mailer view is known to the class because it's name is the same as the mailer method. So for example, in our example from above, our mailer view for the +welcome_email+ method will be in +app/views/user_mailer/welcome_email.html.erb+ for the HTML version and +welcome_email.text.erb+ for the plain text version. diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index 1de1808bc7..6837c8b11a 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -769,13 +769,13 @@ Even though Active Record lets you specify conditions on the eager loaded associ 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 also have a +locked+ field on the +Client+ model, you also get +find_by_locked+ and +find_all_by_locked+. +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. -You can do +find_last_by_*+ methods too which will find the last record matching your argument. +You can also use +find_last_by_*+ methods which will find the last record matching your argument. You can specify an exclamation point (<tt>!</tt>) on the end of the dynamic finders to get them to raise an +ActiveRecord::RecordNotFound+ error if they do not return any records, like +Client.find_by_name!("Ryan")+ -If you want to find both by name and locked, you can chain these finders together by simply typing +and+ between the fields for example +Client.find_by_first_name_and_locked("Ryan", true)+. +If you want to find both by name and locked, you can chain these finders together by simply typing +and+ between the fields. For example, +Client.find_by_first_name_and_locked("Ryan", true)+. There's another set of dynamic finders that let you find or create/initialize objects if they aren't found. These work in a similar fashion to the other finders and can be used like +find_or_create_by_first_name(params[:first_name])+. Using this will first perform a find and then create if the find returns +nil+. The SQL looks like this for +Client.find_or_create_by_first_name("Ryan")+: diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile index dbef9463a9..6996dab8c5 100644 --- a/railties/guides/source/association_basics.textile +++ b/railties/guides/source/association_basics.textile @@ -30,7 +30,7 @@ Now, suppose we wanted to add a new order for an existing customer. We'd need to Or consider deleting a customer, and ensuring that all of its orders get deleted as well: <ruby> -@orders = Order.find_all_by_customer_id(@customer.id) +@orders = Order.where(:customer_id => @customer.id) @orders.each do |order| order.destroy end @@ -550,7 +550,7 @@ build_customer create_customer </ruby> -h6. <tt>_association_(force_reload = false)</tt> +h6(#belongs_to-association). <tt>_association_(force_reload = false)</tt> The <tt><em>association</em></tt> method returns the associated object, if any. If no associated object is found, it returns +nil+. @@ -560,7 +560,7 @@ The <tt><em>association</em></tt> method returns the associated object, if any. If the associated object has already been retrieved from the database for this object, the cached version will be returned. To override this behavior (and force a database read), pass +true+ as the +force_reload+ argument. -h6. <tt>_association_=(associate)</tt> +h6(#belongs_to-association_equal). <tt>_association_=(associate)</tt> The <tt><em>association</em>=</tt> method assigns an associated object to this object. Behind the scenes, this means extracting the primary key from the associate object and setting this object's foreign key to the same value. @@ -637,7 +637,7 @@ class Order < ActiveRecord::Base end </ruby> -h6. +:counter_cache+ +h6(#belongs_to-counter_cache). +:counter_cache+ The +:counter_cache+ option can be used to make finding the number of belonging objects more efficient. Consider these models: @@ -733,7 +733,7 @@ end NOTE: There's no need to use +:include+ for immediate associations - that is, if you have +Order belongs_to :customer+, then the customer is eager-loaded automatically when it's needed. -h6. +:polymorphic+ +h6(#belongs_to-polymorphic). +:polymorphic+ Passing +true+ to the +:polymorphic+ option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail <a href="#polymorphic-associations">earlier in this guide</a>. @@ -747,7 +747,7 @@ The +:select+ option lets you override the SQL +SELECT+ clause that is used to r TIP: If you set the +:select+ option on a +belongs_to+ association, you should also set the +foreign_key+ option to guarantee the correct results. -h6. +:touch+ +h6(#belongs_to-touch). +:touch+ If you set the +:touch+ option to +:true+, then the +updated_at+ or +updated_on+ timestamp on the associated object will be set to the current time whenever this object is saved or destroyed: @@ -817,7 +817,7 @@ build_account create_account </ruby> -h6. <tt><em>association</em>(force_reload = false)</tt> +h6(#has_one-association). <tt><em>association</em>(force_reload = false)</tt> The <tt><em>association</em></tt> method returns the associated object, if any. If no associated object is found, it returns +nil+. @@ -827,7 +827,7 @@ The <tt><em>association</em></tt> method returns the associated object, if any. If the associated object has already been retrieved from the database for this object, the cached version will be returned. To override this behavior (and force a database read), pass +true+ as the +force_reload+ argument. -h6. <tt><em>association</em>=(associate)</tt> +h6(#has_one-association_equal). <tt><em>association</em>=(associate)</tt> The <tt><em>association</em>=</tt> method assigns an associated object to this object. Behind the scenes, this means extracting the primary key from this object and setting the associate object's foreign key to the same value. @@ -1029,6 +1029,7 @@ When you declare a +has_many+ association, the declaring class automatically gai * <tt><em>collection</em>.empty?</tt> * <tt><em>collection</em>.size</tt> * <tt><em>collection</em>.find(...)</tt> +* <tt><em>collection</em>.where(...)</tt> * <tt><em>collection</em>.exists?(...)</tt> * <tt><em>collection</em>.build(attributes = {}, ...)</tt> * <tt><em>collection</em>.create(attributes = {})</tt> @@ -1054,6 +1055,7 @@ orders.clear orders.empty? orders.size orders.find(...) +orders.where(...) orders.exists?(...) orders.build(attributes = {}, ...) orders.create(attributes = {}) @@ -1083,10 +1085,10 @@ The <tt><em>collection</em>.delete</tt> method removes one or more objects from @customer.orders.delete(@order1) </ruby> -WARNING: Objects will be in addition destroyed if they're associated with +:dependent => :destroy+, and deleted if they're associated with +:dependent => :delete_all+. +WARNING: Additionally, objects will be destroyed if they're associated with +:dependent => :destroy+, and deleted if they're associated with +:dependent => :delete_all+. -h6(#has_many-collection_equal). <tt><em>collection</em>=objects</tt> +h6(#has_many-collection-equal). <tt><em>collection</em>=objects</tt> The <tt><em>collection</em>=</tt> method makes the collection contain only the supplied objects, by adding and deleting as appropriate. @@ -1102,11 +1104,11 @@ h6(#has_many-collection_singular_ids_ids). <tt><em>collection_singular</em>_ids= The <tt><em>collection_singular</em>_ids=</tt> method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. -h6(#has_many-collection_clear). <tt><em>collection</em>.clear</tt> +h6(#has_many-collection-clear). <tt><em>collection</em>.clear</tt> The <tt><em>collection</em>.clear</tt> method removes every object from the collection. This destroys the associated objects if they are associated with +:dependent => :destroy+, deletes them directly from the database if +:dependent => :delete_all+, and otherwise sets their foreign keys to +NULL+. -h6. <tt><em>collection</em>.empty?</tt> +h6(#has_many-collection-empty). <tt><em>collection</em>.empty?</tt> The <tt><em>collection</em>.empty?</tt> method returns +true+ if the collection does not contain any associated objects. @@ -1116,7 +1118,7 @@ The <tt><em>collection</em>.empty?</tt> method returns +true+ if the collection <% end %> </ruby> -h6. <tt><em>collection</em>.size</tt> +h6(#has_many-collection-size). <tt><em>collection</em>.size</tt> The <tt><em>collection</em>.size</tt> method returns the number of objects in the collection. @@ -1124,7 +1126,7 @@ The <tt><em>collection</em>.size</tt> method returns the number of objects in th @order_count = @customer.orders.size </ruby> -h6. <tt><em>collection</em>.find(...)</tt> +h6(#has_many-collection-find). <tt><em>collection</em>.find(...)</tt> The <tt><em>collection</em>.find</tt> method finds objects within the collection. It uses the same syntax and options as +ActiveRecord::Base.find+. @@ -1132,11 +1134,22 @@ The <tt><em>collection</em>.find</tt> method finds objects within the collection @open_orders = @customer.orders.find(:all, :conditions => "open = 1") </ruby> -h6. <tt><em>collection</em>.exists?(...)</tt> +NOTE: Starting Rails 3, supplying options to +ActiveRecord::Base.find+ method is discouraged. Use <tt><em>collection</em>.where</tt> instead when you need to pass conditions. + +h6(#has_many-collection-where). <tt><em>collection</em>.where(...)</tt> + +The <tt><em>collection</em>.where</tt> method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed. + +<ruby> +@open_orders = @customer.orders.where(:open => true) # No query yet +@open_order = @open_orders.first # Now the database will be queried +</ruby> + +h6(#has_many-collection-exists). <tt><em>collection</em>.exists?(...)</tt> The <tt><em>collection</em>.exists?</tt> method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as +ActiveRecord::Base.exists?+. -h6(#has_many_collection_build). <tt><em>collection</em>.build(attributes = {}, ...)</tt> +h6(#has_many-collection-build). <tt><em>collection</em>.build(attributes = {}, ...)</tt> The <tt><em>collection</em>.build</tt> method returns one or more new objects of the associated type. These objects will be instantiated from the passed attributes, and the link through their foreign key will be created, but the associated objects will _not_ yet be saved. @@ -1145,7 +1158,7 @@ The <tt><em>collection</em>.build</tt> method returns one or more new objects of :order_number => "A12345") </ruby> -h6. <tt><em>collection</em>.create(attributes = {})</tt> +h6(#has_many-collection-create). <tt><em>collection</em>.create(attributes = {})</tt> The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be created, and the associated object _will_ be saved (assuming that it passes any validations). @@ -1193,7 +1206,7 @@ h6(#has_many-as). +:as+ Setting the +:as+ option indicates that this is a polymorphic association, as discussed <a href="#polymorphic-associations">earlier in this guide</a>. -h6. +:autosave+ +h6(#has_many-autosave). +:autosave+ If you set the +:autosave+ option to +true+, Rails will save any loaded members and destroy members that are marked for destruction whenever you save the parent object. @@ -1439,11 +1452,12 @@ When you declare a +has_and_belongs_to_many+ association, the declaring class au * <tt><em>collection</em>.empty?</tt> * <tt><em>collection</em>.size</tt> * <tt><em>collection</em>.find(...)</tt> +* <tt><em>collection</em>.where(...)</tt> * <tt><em>collection</em>.exists?(...)</tt> * <tt><em>collection</em>.build(attributes = {})</tt> * <tt><em>collection</em>.create(attributes = {})</tt> -In all of these methods, <tt><em>collection</em></tt> is replaced with the symbol passed as the first argument to +has_and_belongs_to_many+, and <tt><em>collection_singular</em></tt> is replaced with the singularized version of that symbol.. For example, given the declaration: +In all of these methods, <tt><em>collection</em></tt> is replaced with the symbol passed as the first argument to +has_and_belongs_to_many+, and <tt><em>collection_singular</em></tt> is replaced with the singularized version of that symbol. For example, given the declaration: <ruby> class Part < ActiveRecord::Base @@ -1464,6 +1478,7 @@ assemblies.clear assemblies.empty? assemblies.size assemblies.find(...) +assemblies.where(...) assemblies.exists?(...) assemblies.build(attributes = {}, ...) assemblies.create(attributes = {}) @@ -1476,7 +1491,7 @@ If the join table for a +has_and_belongs_to_many+ association has additional col WARNING: The use of extra attributes on the join table in a +has_and_belongs_to_many+ association is deprecated. If you require this sort of complex behavior on the table that joins two models in a many-to-many relationship, you should use a +has_many :through+ association instead of +has_and_belongs_to_many+. -h6. <tt><em>collection</em>(force_reload = false)</tt> +h6(#has_and_belongs_to_many-collection). <tt><em>collection</em>(force_reload = false)</tt> The <tt><em>collection</em></tt> method returns an array of all of the associated objects. If there are no associated objects, it returns an empty array. @@ -1484,7 +1499,7 @@ The <tt><em>collection</em></tt> method returns an array of all of the associate @assemblies = @part.assemblies </ruby> -h6. <tt><em>collection</em><<(object, ...)</tt> +h6(#has_and_belongs_to_many-collection-lt_lt). <tt><em>collection</em><<(object, ...)</tt> The <tt><em>collection</em><<</tt> method adds one or more objects to the collection by creating records in the join table. @@ -1494,7 +1509,7 @@ The <tt><em>collection</em><<</tt> method adds one or more objects to the collec NOTE: This method is aliased as <tt><em>collection</em>.concat</tt> and <tt><em>collection</em>.push</tt>. -h6. <tt><em>collection</em>.delete(object, ...)</tt> +h6(#has_and_belongs_to_many-collection-delete). <tt><em>collection</em>.delete(object, ...)</tt> The <tt><em>collection</em>.delete</tt> method removes one or more objects from the collection by deleting records in the join table. This does not destroy the objects. @@ -1502,11 +1517,11 @@ The <tt><em>collection</em>.delete</tt> method removes one or more objects from @part.assemblies.delete(@assembly1) </ruby> -h6. <tt><em>collection</em>=objects</tt> +h6(#has_and_belongs_to_many-collection-equal). <tt><em>collection</em>=objects</tt> The <tt><em>collection</em>=</tt> method makes the collection contain only the supplied objects, by adding and deleting as appropriate. -h6. <tt><em>collection_singular</em>_ids</tt> +h6(#has_and_belongs_to_many-collection_singular). <tt><em>collection_singular</em>_ids</tt> The <tt><em>collection_singular</em>_ids</tt> method returns an array of the ids of the objects in the collection. @@ -1514,11 +1529,11 @@ The <tt><em>collection_singular</em>_ids</tt> method returns an array of the ids @assembly_ids = @part.assembly_ids </ruby> -h6. <tt><em>collection_singular</em>_ids=ids</tt> +h6(#has_and_belongs_to_many-collection_singular_ids_ids). <tt><em>collection_singular</em>_ids=ids</tt> The <tt><em>collection_singular</em>_ids=</tt> method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. -h6. <tt><em>collection</em>.clear</tt> +h6(#has_and_belongs_to_many-collection-clear). <tt><em>collection</em>.clear</tt> The <tt><em>collection</em>.clear</tt> method removes every object from the collection by deleting the rows from the joining table. This does not destroy the associated objects. @@ -1549,6 +1564,16 @@ The <tt><em>collection</em>.find</tt> method finds objects within the collection :conditions => ["created_at > ?", 2.days.ago]) </ruby> +NOTE: Starting Rails 3, supplying options to +ActiveRecord::Base.find+ method is discouraged. Use <tt><em>collection</em>.where</tt> instead when you need to pass conditions. + +h6(#has_and_belongs_to_many-collection-where). <tt><em>collection</em>.where(...)</tt> + +The <tt><em>collection</em>.where</tt> method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed. It also adds the additional condition that the object must be in the collection. + +<ruby> +@new_assemblies = @part.assemblies.where("created_at > ?", 2.days.ago) +</ruby> + h6(#has_and_belongs_to_many-collection-exists). <tt><em>collection</em>.exists?(...)</tt> The <tt><em>collection</em>.exists?</tt> method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as +ActiveRecord::Base.exists?+. @@ -1605,7 +1630,7 @@ The +has_and_belongs_to_many+ association supports these options: * +:uniq+ * +:validate+ -h6. +:association_foreign_key+ +h6(#has_and_belongs_to_many-association_foreign_key). +:association_foreign_key+ By convention, Rails guesses that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix +_id+ added. The +:association_foreign_key+ option lets you set the name of the foreign key directly: @@ -1661,7 +1686,7 @@ Normally Rails automatically generates the proper SQL to count the association m NOTE: If you specify +:finder_sql+ but not +:counter_sql+, then the counter SQL will be generated by substituting +SELECT COUNT(*) FROM+ for the +SELECT ... FROM+ clause of your +:finder_sql+ statement. -h6. +:delete_sql+ +h6(#has_and_belongs_to_many-delete_sql). +:delete_sql+ Normally Rails automatically generates the proper SQL to remove links between the associated classes. With the +:delete_sql+ option, you can specify a complete SQL statement to delete them yourself. @@ -1699,11 +1724,11 @@ h6(#has_and_belongs_to_many-include). +:include+ You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. -h6. +:insert_sql+ +h6(#has_and_belongs_to_many-insert_sql). +:insert_sql+ Normally Rails automatically generates the proper SQL to create links between the associated classes. With the +:insert_sql+ option, you can specify a complete SQL statement to insert them yourself. -h6. +:join_table+ +h6(#has_and_belongs_to_many-join_table). +:join_table+ If the default name of the join table, based on lexical ordering, is not what you want, you can use the +:join_table+ option to override the default. @@ -1821,7 +1846,7 @@ If you have an extension that should be shared by many associations, you can use <ruby> module FindRecentExtension def find_recent - find(:all, :conditions => ["created_at > ?", 5.days.ago]) + where("created_at > ?", 5.days.ago) end end diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index 09cd796271..3320b610e7 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -362,20 +362,9 @@ class ProductsController < ApplicationController end </ruby> -h3. Advanced Caching - -Along with the built-in mechanisms outlined above, a number of excellent plugins exist to help with finer grained control over caching. These include Chris Wanstrath's excellent cache_fu plugin (more info "here":http://errtheblog.com/posts/57-kickin-ass-w-cachefu ) and Evan Weaver's interlock plugin (more info "here":http://blog.evanweaver.com/articles/2007/12/13/better-rails-caching/ ). Both of these plugins play nice with memcached and are a must-see for anyone -seriously considering optimizing their caching needs. - -Also the new "Cache money":http://github.com/ngmoco/cache-money/tree/rails3 plugin is supposed to be mad cool. - -h3. References +h3. Further reading * "Scaling Rails Screencasts":http://railslab.newrelic.com/scaling-rails -* "RailsEnvy, Rails Caching Tutorial, Part 1":http://www.railsenvy.com/2007/2/28/rails-caching-tutorial -* "RailsEnvy, Rails Caching Tutorial, Part 2":http://www.railsenvy.com/2007/3/20/ruby-on-rails-caching-tutorial-part-2 -* "ActiveSupport::Cache documentation":http://api.rubyonrails.org/classes/ActiveSupport/Cache.html -* "Rails 2.1 integrated caching tutorial":http://thewebfellas.com/blog/2008/6/9/rails-2-1-now-with-better-integrated-caching h3. Changelog diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index e3b9d745b2..ce0f66b2c1 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -31,17 +31,18 @@ When called without arguments like this, it creates a form element that has the Sample output from +form_tag+: <html> -<form action="/home/index" method="post"> +<form accept-charset="UTF-8" action="/home/index" method="post"> <div style="margin:0;padding:0"> + <input name="utf8" type="hidden" value="✓" /> <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" /> </div> Form contents </form> </html> -If you carefully observe this output, you can see that the helper generated something you didn't specify: a +div+ element with a hidden input inside. This is a security feature of Rails called *cross-site request forgery protection* and form helpers generate it for every form whose action is not "get" (provided that this security feature is enabled). You can read more about this in the "Ruby On Rails Security Guide":./security.html#_cross_site_reference_forgery_csrf. +If you carefully observe this output, you can see that the helper generated something you didn't specify: a +div+ element with two hidden input elements inside. The first input element with name +utf8+ enforces browsers to properly respect your form's character encoding and is generated for all forms whether action is "get" or "post". Second input element with name +authenticity_token+ is a security feature of Rails called *cross-site request forgery protection* and form helpers generate it for every form whose action is not "get" (provided that this security feature is enabled). You can read more about this in the "Ruby On Rails Security Guide":./security.html#_cross_site_reference_forgery_csrf. -NOTE: Throughout this guide, this +div+ with the hidden input will be stripped away to have clearer code samples. +NOTE: Throughout this guide, this +div+ with the hidden input elements will be stripped away to have clearer code samples. h4. A Generic Search Form @@ -71,7 +72,7 @@ TIP: +search_path+ can be a named route specified in "routes.rb": <br /><tt>map. The above view code will result in the following markup: <html> -<form action="/search" method="get"> +<form accept-charset="UTF-8" action="/search" method="get"> <label for="q">Search for:</label> <input id="q" name="q" type="text" /> <input name="commit" type="submit" value="Search" /> @@ -90,14 +91,14 @@ As with the +link_to+ helper, the path argument doesn't have to be given a strin <ruby> form_tag(:controller => "people", :action => "search", :method => "get", :class => "nifty_form") -# => <form action="/people/search?method=get&class=nifty_form" method="post"> +# => <form accept-charset="UTF-8" action="/people/search?method=get&class=nifty_form" method="post"> </ruby> Here you wanted to pass two hashes, but the Ruby interpreter sees only one hash, so Rails will construct a URL with extraneous parameters. The correct way of passing multiple hashes as arguments is to delimit the first hash (or both hashes) with curly brackets: <ruby> form_tag({:controller => "people", :action => "search"}, :method => "get", :class => "nifty_form") -# => <form action="/people/search" method="get" class="nifty_form"> +# => <form accept-charset="UTF-8" action="/people/search" method="get" class="nifty_form"> </ruby> This is a common pitfall when using form helpers, since many of them accept multiple hashes. So in future, if a helper produces unexpected output, make sure that you have delimited the hash parameters properly. @@ -239,7 +240,7 @@ There are a few things to note here: The resulting HTML is: <html> -<form action="/articles/create" method="post" class="nifty_form"> +<form accept-charset="UTF-8" action="/articles/create" method="post" class="nifty_form"> <input id="article_title" name="article[title]" size="30" type="text" /> <textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea> <input name="commit" type="submit" value="Create" /> @@ -264,7 +265,7 @@ You can create a similar binding without actually creating +<form>+ tags which produces the following output: <html> -<form action="/people/create" class="new_person" id="new_person" method="post"> +<form accept-charset="UTF-8" action="/people/create" class="new_person" id="new_person" method="post"> <input id="person_name" name="person[name]" size="30" type="text" /> <input id="contact_detail_phone_number" name="contact_detail[phone_number]" size="30" type="text" /> </form> @@ -334,9 +335,10 @@ form_tag(search_path, :method => "put") output: <html> -<form action="/search" method="post"> +<form accept-charset="UTF-8" action="/search" method="post"> <div style="margin:0;padding:0"> <input name="_method" type="hidden" value="put" /> + <input name="utf8" type="hidden" value="✓" /> <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" /> </div> ... @@ -633,7 +635,12 @@ action for a Person model, +params[:model]+ would usually be a hash of all the a Fundamentally HTML forms don't know about any sort of structured data, all they generate is name–value pairs, where pairs are just plain strings. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses. -TIP: You may find you can try out examples in this section faster by using the console to directly invoke Rails' parameter parser. For example <tt> ActionController::UrlEncodedPairParser.parse_query_parameters "name=fred&phone=0123456789" # => {"name"=>"fred", "phone"=>"0123456789"} </tt> +TIP: You may find you can try out examples in this section faster by using the console to directly invoke Rails' parameter parser. For example, + +<ruby> +ActionController::UrlEncodedPairParser.parse_query_parameters "name=fred&phone=0123456789" +# => {"name"=>"fred", "phone"=>"0123456789"} +</ruby> h4. Basic Structures @@ -709,7 +716,7 @@ You might want to render a form with a set of edit fields for each of a person's Assuming the person had two addresses, with ids 23 and 45 this would create output similar to this: <html> -<form action="/people/1" class="edit_person" id="edit_person_1" method="post"> +<form accept-charset="UTF-8" action="/people/1" class="edit_person" id="edit_person_1" method="post"> <input id="person_name" name="person[name]" size="30" type="text" /> <input id="person_address_23_city" name="person[address][23][city]" size="30" type="text" /> <input id="person_address_45_city" name="person[address][45][city]" size="30" type="text" /> diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index 14107eb6f5..50c5986a64 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -27,7 +27,7 @@ I'll cover each of these methods in turn. But first, a few words about the very h4. Rendering by Default: Convention Over Configuration in Action -You've heard that Rails promotes "convention over configuration." Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your +BooksController+ class: +You've heard that Rails promotes "convention over configuration". Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your +BooksController+ class: <ruby> class BooksController < ApplicationController @@ -46,7 +46,7 @@ And you have a view file +app/views/books/index.html.erb+: <h1>Books are coming soon!</h1> </ruby> -Rails will automatically render +app/views/books/index.html.erb+ when you navigate to +/books+ and you will see on your screen that "Books are coming soon!" +Rails will automatically render +app/views/books/index.html.erb+ when you navigate to +/books+ and you will see "Books are coming soon!" on your screen. However a coming soon screen is only minimally useful, so you will soon create your +Book+ model and add the index action to +BooksController+: @@ -58,9 +58,9 @@ class BooksController < ApplicationController end </ruby> -Note that again, we have convention over configuration, in that there is no explicit render at the end of this index action. The rule is that if you do not explicitly render something by the end of the controller action, rails will look for the +action_name.html.erb+ template in the controllers view path and then render that, so in this case, Rails will render the +app/views/books/index.html.erb+ file. +Note that we don't have explicit render at the end of the index action in accordance with "convention over configuration" principle. The rule is that if you do not explicitly render something at the end of a controller action, Rails will automatically look for the +action_name.html.erb+ template in the controller's view path and render it. So in this case, Rails will render the +app/views/books/index.html.erb+ file. -So in our view, we want to display the properties of all the books, we could do this with an ERB template like this: +If we want to display the properties of all the books in our view, we can do so with an ERB template like this: <ruby> <h1>Listing Books</h1> @@ -123,7 +123,7 @@ Cache-Control: no-cache $ </shell> -We see there is an empty response (no data after the +Cache-Control+ line), but that Rails has set the response to 200 OK, so the request was successful. You can set the +:status+ options on render to change this response. Rendering nothing can be useful for AJAX requests where all you want to send back to the browser is an acknowledgement that the request was completed. +We see there is an empty response (no data after the +Cache-Control+ line), but the request was successful because Rails has set the response to 200 OK. You can set the +:status+ options on render to change this response. Rendering nothing can be useful for AJAX requests where all you want to send back to the browser is an acknowledgement that the request was completed. TIP: You should probably be using the +head+ method, discussed later in this guide, instead of +render :nothing+. This provides additional flexibility and makes it explicit that you're only generating HTTP headers. @@ -134,11 +134,10 @@ If you want to render the view that corresponds to a different action within the <ruby> def update @book = Book.find(params[:id]) - if @book.update_attributes(params[:book]) - redirect_to(@book) - else - render "edit" - end + if @book.update_attributes(params[:book]) + redirect_to(@book) + else + render "edit" end end </ruby> @@ -150,11 +149,10 @@ If you prefer, you can use a symbol instead of a string to specify the action to <ruby> def update @book = Book.find(params[:id]) - if @book.update_attributes(params[:book]) - redirect_to(@book) - else - render :edit - end + if @book.update_attributes(params[:book]) + redirect_to(@book) + else + render :edit end end </ruby> @@ -164,11 +162,10 @@ To be explicit, you can use +render+ with the +:action+ option (though this is n <ruby> def update @book = Book.find(params[:id]) - if @book.update_attributes(params[:book]) - redirect_to(@book) - else - render :action => "edit" - end + if @book.update_attributes(params[:book]) + redirect_to(@book) + else + render :action => "edit" end end </ruby> @@ -208,13 +205,13 @@ The +:file+ option takes an absolute file-system path. Of course, you need to ha NOTE: By default, the file is rendered without using the current layout. If you want Rails to put the file into the current layout, you need to add the +:layout => true+ option. -TIP: If you're running on Microsoft Windows, you should use the +:file+ option to render a file, because Windows filenames do not have the same format as Unix filenames. +TIP: If you're running Rails on Microsoft Windows, you should use the +:file+ option to render a file, because Windows filenames do not have the same format as Unix filenames. h5. Wrapping it up -The above three methods of render (rendering another template within the controller, rendering a template within another controller and rendering an arbitrary file on the file system) are actually all variants of the same action. +The above three ways of rendering (rendering another template within the controller, rendering a template within another controller and rendering an arbitrary file on the file system) are actually variants of the same action. -In fact, in the BooksController method, inside of the edit action where we want to render the edit template if the book does not update successfully, all of the following render calls would all render the +edit.html.erb+ template in the +views/books+ directory: +In fact, in the BooksController class, inside of the edit action where we want to render the edit template if the book does not update successfully, all of the following render calls would all render the +edit.html.erb+ template in the +views/books+ directory: <ruby> render :edit @@ -241,12 +238,12 @@ The +render+ method can do without a view completely, if you're willing to use t <ruby> render :inline => - "<% products.each do |p| %><p><%= p.name %><p><% end %>" + "<% products.each do |p| %><p><%= p.name %></p><% end %>" </ruby> WARNING: There is seldom any good reason to use this option. Mixing ERB into your controllers defeats the MVC orientation of Rails and will make it harder for other developers to follow the logic of your project. Use a separate erb view instead. -By default, inline rendering uses ERb. You can force it to use Builder instead with the +:type+ option: +By default, inline rendering uses ERB. You can force it to use Builder instead with the +:type+ option: <ruby> render :inline => @@ -275,7 +272,7 @@ render :text => "OK" TIP: Rendering pure text is most useful when you're responding to AJAX or web service requests that are expecting something other than proper HTML. -NOTE: By default, if you use the +:text+ option the text is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the +:layout => true+ option. +NOTE: By default, if you use the +:text+ option, the text is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the +:layout => true+ option. h5. Rendering JSON @@ -498,7 +495,7 @@ def show end </ruby> -If +@book.special?+ evaluates to +true+, Rails will start the rendering process to dump the +@book+ variable into the +special_show+ view. But this will _not_ stop the rest of the code in the +show+ action from running, and when Rails hits the end of the action, it will start to render the +show+ view - and throw an error. The solution is simple: make sure that you only have one call to +render+ or +redirect+ in a single code path. One thing that can help is +and return+. Here's a patched version of the method: +If +@book.special?+ evaluates to +true+, Rails will start the rendering process to dump the +@book+ variable into the +special_show+ view. But this will _not_ stop the rest of the code in the +show+ action from running, and when Rails hits the end of the action, it will start to render the +regular_show+ view - and throw an error. The solution is simple: make sure that you have only one call to +render+ or +redirect+ in a single code path. One thing that can help is +and return+. Here's a patched version of the method: <ruby> def show @@ -568,7 +565,7 @@ def show end </ruby> -With the code in this form, there will be likely be a problem if the +@book+ variable is +nil+. Remember, a +render :action+ doesn't run any code in the target action, so nothing will set up the +@books+ variable that the +index+ view is presumably depending on. One way to fix this is to redirect instead of rendering: +With the code in this form, there will likely be a problem if the +@book+ variable is +nil+. Remember, a +render :action+ doesn't run any code in the target action, so nothing will set up the +@books+ variable that the +index+ view is presumably depending on. One way to fix this is to redirect instead of rendering: <ruby> def index @@ -585,7 +582,7 @@ end With this code, the browser will make a fresh request for the index page, the code in the +index+ method will run, and all will be well. -The only downside to this code, is that it requires a round trip to the browser, the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 301 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen. +The only downside to this code, is that it requires a round trip to the browser, the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen. While in a small app, this added latency might not be a problem, it is something to think about when speed of response is of the essence. One way to handle this double request (though a contrived example) could be: @@ -603,7 +600,7 @@ def show end </ruby> -Which would detect that there are no books populate the +@books+ instance variable with all the books in the database and then directly render the +index.html.erb+ template returning it to the browser with a flash alert message telling the user what happened. +Which would detect that there are no books, populate the +@books+ instance variable with all the books in the database and then directly render the +index.html.erb+ template returning it to the browser with a flash alert message telling the user what happened. h4. Using +head+ To Build Header-Only Responses @@ -806,7 +803,9 @@ You can even use dynamic paths such as +cache/#{current_site}/main/display+. h5. Linking to Images with +image_tag+ -The +image_tag+ helper builds an HTML +<img />+ tag to the specified file. By default, files are loaded from +public/images+, note, you must specify the extension, previous versions of Rails would allow you to just call the image name and would append +.png+ if no extension was given, Rails 3.0 does not. +The +image_tag+ helper builds an HTML +<img />+ tag to the specified file. By default, files are loaded from +public/images+. + +WARNING: Note that you must specify the extension of the image. Previous versions of Rails would allow you to just use the image name and would append +.png+ if no extension was given but Rails 3.0 does not. <erb> <%= image_tag "header.png" %> @@ -843,7 +842,7 @@ You can also specify a special size tag, in the format "{width}x{height}": <%= image_tag "home.gif", :size => "50x20" %> </erb> -In addition to the above special tags, you can supply a final hash of standard HTML options, such as +:class+ or +:id+ or +:name+: +In addition to the above special tags, you can supply a final hash of standard HTML options, such as +:class+, +:id+ or +:name+: <erb> <%= image_tag "home.gif", :alt => "Go Home", @@ -1087,7 +1086,7 @@ Partials are very useful in rendering collections. When you pass a collection to When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered. -In Rails 3.0 there is also a shorthand for this, assuming +@products+ is a collection of +product+ instances, you can simply do in the +index.html.erb+: +In Rails 3.0, there is also a shorthand for this. Assuming +@products+ is a collection of +product+ instances, you can simply write this in the +index.html.erb+: <erb> <h1>Products</h1> diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index cfba58d8da..7d4fb69d3b 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -161,15 +161,15 @@ end This will create a number of routes for each of the +posts+ and +comments+ controller. For +Admin::PostsController+, Rails will create: |_. Verb |_.Path |_.action |_. helper | -|GET |/admin/photos |index | admin_photos_path | -|GET |/admin/photos/new |new | new_admin_photos_path | -|POST |/admin/photos |create | admin_photos_path | -|GET |/admin/photos/1 |show | admin_photo_path(id) | -|GET |/admin/photos/1/edit |edit | edit_admin_photo_path(id) | -|PUT |/admin/photos/1 |update | admin_photo_path(id) | -|DELETE |/admin/photos/1 |destroy | admin_photo_path(id) | +|GET |/admin/posts |index | admin_posts_path | +|GET |/admin/posts/new |new | new_admin_posts_path | +|POST |/admin/posts |create | admin_posts_path | +|GET |/admin/posts/1 |show | admin_post_path(id) | +|GET |/admin/posts/1/edit |edit | edit_admin_post_path(id) | +|PUT |/admin/posts/1 |update | admin_post_path(id) | +|DELETE |/admin/posts/1 |destroy | admin_post_path(id) | -If you want to route +/photos+ (without the prefix +/admin+) to +Admin::PostsController+, you could use +If you want to route +/posts+ (without the prefix +/admin+) to +Admin::PostsController+, you could use <ruby> scope :module => "admin" do @@ -183,7 +183,7 @@ or, for a single case resources :posts, :module => "admin" </ruby> -If you want to route +/admin/photos+ to +PostsController+ (without the +Admin::+ module prefix), you could use +If you want to route +/admin/posts+ to +PostsController+ (without the +Admin::+ module prefix), you could use <ruby> scope "/admin" do @@ -200,13 +200,13 @@ resources :posts, :path => "/admin" In each of these cases, the named routes remain the same as if you did not use +scope+. In the last case, the following paths map to +PostsController+: |_. Verb |_.Path |_.action |_. helper | -|GET |/admin/photos |index | photos_path | -|GET |/admin/photos/new |new | photos_path | -|POST |/admin/photos |create | photos_path | -|GET |/admin/photos/1 |show | photo_path(id) | -|GET |/admin/photos/1/edit |edit | edit_photo_path(id) | -|PUT |/admin/photos/1 |update | photo_path(id) | -|DELETE |/admin/photos/1 |destroy | photo_path(id) | +|GET |/admin/posts |index | posts_path | +|GET |/admin/posts/new |new | posts_path | +|POST |/admin/posts |create | posts_path | +|GET |/admin/posts/1 |show | post_path(id) | +|GET |/admin/posts/1/edit |edit | edit_post_path(id) | +|PUT |/admin/posts/1 |update | post_path(id) | +|DELETE |/admin/posts/1 |destroy | post_path(id) | h4. Nested Resources @@ -589,7 +589,7 @@ The +:controller+ option lets you explicitly specify a controller to use for the resources :photos, :controller => "images" </ruby> -will recognize incoming paths beginning with +/photo+ but route to the +Images+ controller: +will recognize incoming paths beginning with +/photos+ but route to the +Images+ controller: |_. Verb |_.Path |_.action | |GET |/photos |index | @@ -723,7 +723,7 @@ scope(:path_names => { :new => "neu", :edit => "bearbeiten" }) do end </ruby> -Rails now creates routes to the +CategoriesControlleR+. +Rails now creates routes to the +CategoriesController+. |_.HTTP verb|_.Path |_.action | |GET |/kategorien |index | @@ -788,7 +788,7 @@ TIP: You'll find that the output from +rake routes+ is much more readable if you h4. Testing Routes -Routes should be included in your testing strategy (just like the rest of your application). Rails offers three "built-in assertions":http://api.rubyonrails.org/classes/ActionController/Assertions/RoutingAssertions.html designed to make testing routes simpler: +Routes should be included in your testing strategy (just like the rest of your application). Rails offers three "built-in assertions":http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html designed to make testing routes simpler: * +assert_generates+ * +assert_recognizes+ |