diff options
author | Oliver Jakubiec <ojakubiec@gmail.com> | 2013-04-02 18:45:28 -0700 |
---|---|---|
committer | Oliver Jakubiec <ojakubiec@gmail.com> | 2013-04-02 18:45:28 -0700 |
commit | b13789c30cc991e2c0b20f16705a88e45c91dcad (patch) | |
tree | a7dd94d14b8d62c4c48fb89d9a089eeac079a9b1 /guides/source | |
parent | 8917a5b949856f8ef44d03d98470614c8cf8bbee (diff) | |
parent | 919c86d2d5e7b74b96305c0bfb0482bbe61d99f2 (diff) | |
download | rails-b13789c30cc991e2c0b20f16705a88e45c91dcad.tar.gz rails-b13789c30cc991e2c0b20f16705a88e45c91dcad.tar.bz2 rails-b13789c30cc991e2c0b20f16705a88e45c91dcad.zip |
Merge branch 'master' of github.com:lifo/docrails
Diffstat (limited to 'guides/source')
-rw-r--r-- | guides/source/2_2_release_notes.md | 30 | ||||
-rw-r--r-- | guides/source/action_controller_overview.md | 41 | ||||
-rw-r--r-- | guides/source/action_mailer_basics.md | 55 | ||||
-rw-r--r-- | guides/source/active_record_querying.md | 11 | ||||
-rw-r--r-- | guides/source/caching_with_rails.md | 4 | ||||
-rw-r--r-- | guides/source/contributing_to_ruby_on_rails.md | 27 | ||||
-rw-r--r-- | guides/source/debugging_rails_applications.md | 2 | ||||
-rw-r--r-- | guides/source/engines.md | 11 | ||||
-rw-r--r-- | guides/source/form_helpers.md | 26 | ||||
-rw-r--r-- | guides/source/getting_started.md | 2 | ||||
-rw-r--r-- | guides/source/initialization.md | 2 | ||||
-rw-r--r-- | guides/source/testing.md | 176 | ||||
-rw-r--r-- | guides/source/upgrading_ruby_on_rails.md | 33 |
13 files changed, 246 insertions, 174 deletions
diff --git a/guides/source/2_2_release_notes.md b/guides/source/2_2_release_notes.md index cef82f3784..802455f612 100644 --- a/guides/source/2_2_release_notes.md +++ b/guides/source/2_2_release_notes.md @@ -31,20 +31,20 @@ Documentation The internal documentation of Rails, in the form of code comments, has been improved in numerous places. In addition, the [Ruby on Rails Guides](http://guides.rubyonrails.org/) project is the definitive source for information on major Rails components. In its first official release, the Guides page includes: -* [Getting Started with Rails](http://guides.rubyonrails.org/getting_started.html) -* [Rails Database Migrations](http://guides.rubyonrails.org/migrations.html) -* [Active Record Associations](http://guides.rubyonrails.org/association_basics.html) -* [Active Record Query Interface](http://guides.rubyonrails.org/active_record_querying.html) -* [Layouts and Rendering in Rails](http://guides.rubyonrails.org/layouts_and_rendering.html) -* [Action View Form Helpers](http://guides.rubyonrails.org/form_helpers.html) -* [Rails Routing from the Outside In](http://guides.rubyonrails.org/routing.html) -* [Action Controller Overview](http://guides.rubyonrails.org/action_controller_overview.html) -* [Rails Caching](http://guides.rubyonrails.org/caching_with_rails.html) -* [A Guide to Testing Rails Applications](http://guides.rubyonrails.org/testing.html) -* [Securing Rails Applications](http://guides.rubyonrails.org/security.html) -* [Debugging Rails Applications](http://guides.rubyonrails.org/debugging_rails_applications.html) -* [Performance Testing Rails Applications](http://guides.rubyonrails.org/performance_testing.html) -* [The Basics of Creating Rails Plugins](http://guides.rubyonrails.org/plugins.html) +* [Getting Started with Rails](getting_started.html) +* [Rails Database Migrations](migrations.html) +* [Active Record Associations](association_basics.html) +* [Active Record Query Interface](active_record_querying.html) +* [Layouts and Rendering in Rails](layouts_and_rendering.html) +* [Action View Form Helpers](form_helpers.html) +* [Rails Routing from the Outside In](routing.html) +* [Action Controller Overview](action_controller_overview.html) +* [Rails Caching](caching_with_rails.html) +* [A Guide to Testing Rails Applications](testing.html) +* [Securing Rails Applications](security.html) +* [Debugging Rails Applications](debugging_rails_applications.html) +* [Performance Testing Rails Applications](performance_testing.html) +* [The Basics of Creating Rails Plugins](plugins.html) All told, the Guides provide tens of thousands of words of guidance for beginning and intermediate Rails developers. @@ -236,7 +236,7 @@ This will enable recognition of (among others) these routes: * Lead Contributor: [S. Brent Faulkner](http://www.unwwwired.net/) * More information: - * [Rails Routing from the Outside In](http://guides.rubyonrails.org/routing.html#nested-resources) + * [Rails Routing from the Outside In](routing.html#nested-resources) * [What's New in Edge Rails: Shallow Routes](http://ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-shallow-routes) ### Method Arrays for Member or Collection Routes diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 7c88e48fa9..f197591592 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -49,7 +49,7 @@ class ClientsController < ApplicationController end ``` -As an example, if a user goes to `/clients/new` in your application to add a new client, Rails will create an instance of `ClientsController` and run the `new` method. Note that the empty method from the example above could work just fine because Rails will by default render the `new.html.erb` view unless the action says otherwise. The `new` method could make available to the view a `@client` instance variable by creating a new `Client`: +As an example, if a user goes to `/clients/new` in your application to add a new client, Rails will create an instance of `ClientsController` and run the `new` method. Note that the empty method from the example above would work just fine because Rails will by default render the `new.html.erb` view unless the action says otherwise. The `new` method could make available to the view a `@client` instance variable by creating a new `Client`: ```ruby def new @@ -123,21 +123,21 @@ To send a hash you include the key name inside the brackets: </form> ``` -When this form is submitted, the value of `params[:client]` will be `{"name" => "Acme", "phone" => "12345", "address" => {"postcode" => "12345", "city" => "Carrot City"}}`. Note the nested hash in `params[:client][:address]`. +When this form is submitted, the value of `params[:client]` will be `{ "name" => "Acme", "phone" => "12345", "address" => { "postcode" => "12345", "city" => "Carrot City" } }`. Note the nested hash in `params[:client][:address]`. -Note that the `params` hash is actually an instance of `ActiveSupport::HashWithIndifferentAccess`, which acts like a hash that lets you use symbols and strings interchangeably as keys. +Note that the `params` hash is actually an instance of `ActiveSupport::HashWithIndifferentAccess`, which acts like a hash but lets you use symbols and strings interchangeably as keys. ### JSON parameters -If you're writing a web service application, you might find yourself more comfortable on accepting parameters in JSON format. Rails will automatically convert your parameters into `params` hash, which you'll be able to access like you would normally do with form data. +If you're writing a web service application, you might find yourself more comfortable accepting parameters in JSON format. Rails will automatically convert your parameters into the `params` hash, which you can access as you would normally. -So for example, if you are sending this JSON parameter: +So for example, if you are sending this JSON content: ```json { "company": { "name": "acme", "address": "123 Carrot Street" } } ``` -You'll get `params[:company]` as `{ :name => "acme", "address" => "123 Carrot Street" }`. +You'll get `params[:company]` as `{ "name" => "acme", "address" => "123 Carrot Street" }`. 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 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: @@ -148,19 +148,19 @@ Also, if you've turned on `config.wrap_parameters` in your initializer or callin And assume that you're sending the data to `CompaniesController`, it would then be wrapped in `:company` key like this: ```ruby -{ :name => "acme", :address => "123 Carrot Street", :company => { :name => "acme", :address => "123 Carrot Street" }} +{ :name => "acme", :address => "123 Carrot Street", :company => { :name => "acme", :address => "123 Carrot Street" } } ``` You can customize the name of the key or specific parameters you want to wrap by consulting the [API documentation](http://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html) -NOTE: A support for parsing XML parameters has been extracted into a gem named `actionpack-xml_parser` +NOTE: Support for parsing XML parameters has been extracted into a gem named `actionpack-xml_parser` ### Routing Parameters The `params` hash will always contain the `:controller` and `:action` keys, but you should use the methods `controller_name` and `action_name` instead to access these values. Any other parameters defined by the routing, such as `:id` will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the `:status` parameter in a "pretty" URL: ```ruby -match '/clients/:status' => 'clients#index', foo: "bar" +match '/clients/:status' => 'clients#index', foo: 'bar' ``` In this case, when a user opens the URL `/clients/active`, `params[:status]` will be set to "active". When this route is used, `params[:foo]` will also be set to "bar" just like it was passed in the query string. In the same way `params[:action]` will contain "index". @@ -183,7 +183,7 @@ If you define `default_url_options` in `ApplicationController`, as in the exampl ### Strong Parameters -With strong parameters Action Controller parameters are forbidden to +With strong parameters, Action Controller parameters are forbidden to be used in Active Model mass assignments until they have been whitelisted. This means you'll have to make a conscious choice about which attributes to allow for mass updating and thus prevent @@ -204,7 +204,7 @@ class PeopleController < ActionController::Base # This will pass with flying colors as long as there's a person key # in the parameters, otherwise it'll raise a - # ActionController::MissingParameter exception, which will get + # ActionController::ParameterMissing exception, which will get # caught by ActionController::Base and turned into that 400 Bad # Request reply. def update @@ -283,7 +283,7 @@ to having a `name` (any permitted scalar values allowed, too). You want to also use the permitted attributes in the `new` action. This raises the problem that you can't use `require` on the -root-key because normally it does not exist when calling `new`: +root key because normally it does not exist when calling `new`: ```ruby # using `fetch` you can supply a default and use @@ -301,7 +301,7 @@ params.require(:author).permit(:name, books_attributes: [:title, :id, :_destroy] ``` Hashes with integer keys are treated differently and you can declare -the attributes as if they were direct children. You get this kind of +the attributes as if they were direct children. You get these kinds of parameters when you use `accepts_nested_attributes_for` in combination with a `has_many` association: @@ -321,7 +321,7 @@ in mind. It is not meant as a silver bullet to handle all your whitelisting problems. However you can easily mix the API with your own code to adapt to your situation. -Imagine a situation where you want to whitelist an attribute +Imagine a scenario where you want to whitelist an attribute containing a hash with any keys. Using strong parameters you can't allow a hash with any keys but you can use a simple assignment to get the job done: @@ -571,7 +571,7 @@ Note that while for session values you set the key to `nil`, to delete a cookie Rendering xml and json data --------------------------- -ActionController makes it extremely easy to render `xml` or `json` data. If you generate a controller using scaffolding then it would look something like this: +ActionController makes it extremely easy to render `xml` or `json` data. If you've generated a controller using scaffolding, it would look something like this: ```ruby class UsersController < ApplicationController @@ -586,7 +586,7 @@ class UsersController < ApplicationController end ``` -Notice that in the above case code is `render xml: @users` and not `render xml: @users.to_xml`. That is because if the input is not string then rails automatically invokes `to_xml` . +You may notice in the above code that we're using `render xml: @users`, not `render xml: @users.to_xml`. If the object is not a String, then Rails will automatically invoke `to_xml` for us. Filters ------- @@ -609,15 +609,6 @@ class ApplicationController < ActionController::Base redirect_to new_login_url # halts request cycle end end - - # The logged_in? method simply returns true if the user is logged - # in and false otherwise. It does this by "booleanizing" the - # current_user method we created previously using a double ! operator. - # Note that this is not common in Ruby and is discouraged unless you - # really mean to convert something into true or false. - def logged_in? - !!current_user - end end ``` diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index 31182e9aed..698fe30722 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -14,7 +14,7 @@ After reading this guide, you will know: Introduction ------------ -Action Mailer allows you to send emails from your application using a mailer model and views. So, in Rails, emails are used by creating mailers that inherit from `ActionMailer::Base` and live in `app/mailers`. Those mailers have associated views that appear alongside controller views in `app/views`. +Action Mailer allows you to send emails from your application using mailer classes and views. Mailers work very similarly to controllers. They inherit from `ActionMailer::Base` and live in `app/mailers`, and they have associated views that appear in `app/views`. Sending Emails -------------- @@ -34,7 +34,7 @@ invoke test_unit create test/mailers/user_mailer_test.rb ``` -So we got the mailer, the views, and the tests. +A mailer, a views subdirectory, and tests were created. #### Edit the Mailer @@ -46,7 +46,7 @@ class UserMailer < ActionMailer::Base end ``` -Let's add a method called `welcome_email`, that will send an email to the user's registered email address: +Let's add a method called `welcome_email` that will send an email to the user's registered email address: ```ruby class UserMailer < ActionMailer::Base @@ -62,7 +62,7 @@ end Here is a quick explanation of the items presented in the preceding method. For a full list of all available options, please have a look further down at the Complete List of Action Mailer user-settable attributes section. -* `default Hash` - This is a hash of default values for any email you send, in this case we are setting the `:from` header to a value for all messages in this class, this can be overridden on a per email basis +* `default Hash` - This is a hash of default values for any email you send from this mailer. In this case we are setting the `:from` header to a value for all messages in this class. This can be overridden on a per-email basis. * `mail` - The actual email message, we are passing the `:to` and `:subject` headers in. Just like controllers, any instance variables we define in the method become available for use in the views. @@ -91,7 +91,7 @@ Create a file called `welcome_email.html.erb` in `app/views/user_mailer/`. This </html> ``` -It is also a good idea to make a text part for this email. To do this, create a file called `welcome_email.text.erb` in `app/views/user_mailer/`: +It is also a good idea to make a text template for this email. To do this, create a file called `welcome_email.text.erb` in `app/views/user_mailer/`: ```erb Welcome to example.com, <%= @user.name %> @@ -109,18 +109,18 @@ When you call the `mail` method now, Action Mailer will detect the two templates #### Wire It Up So That the System Sends the Email When a User Signs Up -There are several ways to do this, some people create Rails Observers to fire off emails, others do it inside of the User Model. However, mailers are really just another way to render a view. Instead of rendering a view and sending out the HTTP protocol, they are just sending it out through the Email protocols instead. Due to this, it makes sense to just have your controller tell the mailer to send an email when a user is successfully created. +There are several ways to do this. Some people create Rails Observers to fire off emails when things change in your application, others do it using model callbacks. However, mailers are really just another way to render a view. Instead of rendering a view and sending out the HTTP protocol, they are just sending it out through the Email protocol instead. Due to this, it makes sense to just have your controller tell the mailer to send an email when a user is successfully created. Setting this up is painfully simple. -First off, we need to create a simple `User` scaffold: +First, let's create a simple `User` scaffold: ```bash $ rails generate scaffold user name email login $ rake db:migrate ``` -Now that we have a user model to play with, we will just edit the `app/controllers/users_controller.rb` make it instruct the UserMailer to deliver an email to the newly created user by editing the create action and inserting a call to `UserMailer.welcome_email` right after the user is successfully saved: +Now that we have a user model to play with, we will just edit the `app/controllers/users_controller.rb` to make it instruct the UserMailer to deliver an email to the newly created user by editing the create action and inserting a call to `UserMailer.welcome_email` right after the user is successfully saved: ```ruby class UsersController < ApplicationController @@ -145,7 +145,7 @@ class UsersController < ApplicationController end ``` -This provides a much simpler implementation that does not require the registering of observers and the like. +This provides a simple implementation that does not require the registering of observers or creation of model callbacks. The method `welcome_email` returns a `Mail::Message` object which can then just be told `deliver` to send itself out. @@ -216,7 +216,7 @@ NOTE: If you specify an encoding, Mail will assume that your content is already Action Mailer 3.0 makes inline attachments, which involved a lot of hacking in pre 3.0 versions, much simpler and trivial as they should be. -* Firstly, to tell Mail to turn an attachment into an inline attachment, you just call `#inline` on the attachments method within your Mailer: +* First, to tell Mail to turn an attachment into an inline attachment, you just call `#inline` on the attachments method within your Mailer: ```ruby def welcome @@ -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 `"Full Name <email>"`. ```ruby def welcome_email(user) @@ -320,7 +320,7 @@ This will render the template 'another_template.html.erb' for the HTML part and Just like controller views, you can also have mailer layouts. The layout name needs to be the same as your mailer, such as `user_mailer.html.erb` and `user_mailer.text.erb` to be automatically recognized by your mailer as a layout. -In order to use a different file just use: +In order to use a different file, call `layout` in your mailer: ```ruby class UserMailer < ActionMailer::Base @@ -343,7 +343,7 @@ class UserMailer < ActionMailer::Base end ``` -Will render the HTML part using the `my_layout.html.erb` file and the text part with the usual `user_mailer.text.erb` file if it exists. +Will render the HTML template using the `my_layout.html.erb` file and the text template with the usual `user_mailer.text.erb` file if it exists. ### Generating URLs in Action Mailer Views @@ -547,7 +547,7 @@ config.action_mailer.default_options = {from: 'no-replay@example.org'} ### Action Mailer Configuration for GMail -As Action Mailer now uses the Mail gem, this becomes as simple as adding to your `config/environments/$RAILS_ENV.rb` file: +As Action Mailer uses the Mail gem, this becomes as simple as adding to your `config/environments/$RAILS_ENV.rb` file: ```ruby config.action_mailer.delivery_method = :smtp @@ -564,31 +564,8 @@ config.action_mailer.smtp_settings = { Mailer Testing -------------- -By default Action Mailer does not send emails in the test environment. They are just added to the `ActionMailer::Base.deliveries` array. - -Testing mailers normally involves two things: One is that the mail was queued, and the other one that the email is correct. With that in mind, we could test our example mailer from above like so: - -```ruby -class UserMailerTest < ActionMailer::TestCase - def test_welcome_email - user = users(:some_user_in_your_fixtures) - - # Send the email, then test that it got queued - email = UserMailer.welcome_email(user).deliver - assert !ActionMailer::Base.deliveries.empty? - - # Test the body of the sent email contains what we expect it to - assert_equal [user.email], email.to - assert_equal 'Welcome to My Awesome Site', email.subject - assert_match "<h1>Welcome to example.com, #{user.name}</h1>", email.body.to_s - assert_match 'you have joined to example.com community', email.body.to_s - end -end -``` - -In the test we send the email and store the returned object in the `email` variable. We then ensure that it was sent (the first assert), then, in the second batch of assertions, we ensure that the email does indeed contain what we expect. - -NOTE: The `ActionMailer::Base.deliveries` array is only reset automatically in `ActionMailer::TestCase` tests. If you want to have a clean slate outside Action Mailer tests, you can reset it manually with: `ActionMailer::Base.deliveries.clear` +You can find detailed instructions on how to test your mailers in the +[testing guide](testing.html#testing-your-mailers). Intercepting Emails ------------------- diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index fcdb342a03..2589accadd 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -76,6 +76,7 @@ The methods are: * `reorder` * `reverse_order` * `select` +* `distinct` * `uniq` * `where` @@ -576,10 +577,10 @@ 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. -If you would like to only grab a single record per unique value in a certain field, you can use `uniq`: +If you would like to only grab a single record per unique value in a certain field, you can use `distinct`: ```ruby -Client.select(:name).uniq +Client.select(:name).distinct ``` This would generate SQL like: @@ -591,10 +592,10 @@ SELECT DISTINCT name FROM clients You can also remove the uniqueness constraint: ```ruby -query = Client.select(:name).uniq +query = Client.select(:name).distinct # => Returns unique names -query.uniq(false) +query.distinct(false) # => Returns all names, even if there are duplicates ``` @@ -1434,7 +1435,7 @@ Client.where(active: true).pluck(:id) # SELECT id FROM clients WHERE active = 1 # => [1, 2, 3] -Client.uniq.pluck(:role) +Client.distinct.pluck(:role) # SELECT DISTINCT role FROM clients # => ['admin', 'member', 'guest'] diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index abab3dd983..e1fc3d0f53 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -5,8 +5,8 @@ This guide will teach you what you need to know about avoiding that expensive ro After reading this guide, you will know: -* Page, action, and fragment caching. -* Sweepers. +* Page and action caching (moved to separate gems as of Rails 4). +* Fragment caching. * Alternative cache stores. * Conditional GET support. diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index c6984b4a41..b6363bdfb1 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -53,6 +53,22 @@ The easiest and recommended way to get a development environment ready to hack i In case you can't use the Rails development box, see section above, check [this other guide](development_dependencies_install.html). + +Running an Application Against Your Local Branch +------------------------------------------------ + +The `--dev` flag of `rails new` generates an application that uses your local +branch: + +```bash +$ cd rails +$ bundle exec rails new ~/my-test-app --dev +``` + +The application generated in `~/my-test-app` runs against your local branch +and in particular sees any modifications upon server reboot. + + Testing Active Record --------------------- @@ -201,6 +217,17 @@ Now get busy and add or edit code. You’re on your branch now, so you can write * Include tests that fail without your code, and pass with it. * Update the (surrounding) documentation, examples elsewhere, and the guides: whatever is affected by your contribution. +It is not customary in Rails to run the full test suite before pushing +changes. The railties test suite in particular takes a long time, and even +more if the source code is mounted in `/vagrant` as happens in the recommended +workflow with the [rails-dev-box](https://github.com/rails/rails-dev-box). + +As a compromise, test what your code obviously affects, and if the change is +not in railties run the whole test suite of the affected component. If all is +green that's enough to propose your contribution. We have [Travis CI](https +://travis-ci.org/) as a safety net for catching unexpected breakages +elsewhere. + TIP: Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of Rails will generally not be accepted. ### Follow the Coding Conventions diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 6699098e51..31f96372ec 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -665,7 +665,7 @@ References * [ruby-debug Homepage](http://bashdb.sourceforge.net/ruby-debug/home-page.html) * [debugger Homepage](https://github.com/cldwalker/debugger) -* [Article: Debugging a Rails application with ruby-debug](http://www.sitepoint.com/article/debug-rails-app-ruby-debug/) +* [Article: Debugging a Rails application with ruby-debug](http://www.sitepoint.com/debug-rails-app-ruby-debug/) * [ruby-debug Basics screencast](http://brian.maybeyoureinsane.net/blog/2007/05/07/ruby-debug-basics-screencast/) * [Ryan Bates' debugging ruby (revised) screencast](http://railscasts.com/episodes/54-debugging-ruby-revised) * [Ryan Bates' stack trace screencast](http://railscasts.com/episodes/24-the-stack-trace) diff --git a/guides/source/engines.md b/guides/source/engines.md index 00939c4ff2..22c090e04b 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -461,7 +461,7 @@ NOTE: Other engines, such as Devise, handle this a little differently by making The engine contains migrations for the `blorgh_posts` and `blorgh_comments` table which need to be created in the application's database so that the engine's models can query them correctly. To copy these migrations into the application use this command: ```bash -$ rake blorgh:install:migrations +$ rake blorgh_engine:install:migrations ``` If you have multiple engines that need migrations copied over, use `railties:install:migrations` instead: @@ -676,7 +676,12 @@ There are now no strict dependencies on what the class is, only what the API for Within an engine, there may come a time where you wish to use things such as initializers, internationalization or other configuration options. The great news is that these things are entirely possible because a Rails engine shares much the same functionality as a Rails application. In fact, a Rails application's functionality is actually a superset of what is provided by engines! -If you wish to use an initializer — code that should run before the engine is loaded — the place for it is the `config/initializers` folder. This directory's functionality is explained in the [Initializers section](http://guides.rubyonrails.org/configuring.html#initializers) of the Configuring guide, and works precisely the same way as the `config/initializers` directory inside an application. Same goes for if you want to use a standard initializer. +If you wish to use an initializer — code that should run before the engine is +loaded — the place for it is the `config/initializers` folder. This directory's +functionality is explained in the +[Initializers section](configuring.html#initializers) of the Configuring guide, +and works precisely the same way as the `config/initializers` directory inside +an application. Same goes for if you want to use a standard initializer. For locales, simply place the locale files in the `config/locales` directory, just like you would in an application. @@ -918,7 +923,7 @@ initializer "blorgh.assets.precompile" do |app| end ``` -For more information, read the [Asset Pipeline guide](http://guides.rubyonrails.org/asset_pipeline.html) +For more information, read the [Asset Pipeline guide](asset_pipeline.html) ### Other gem dependencies diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 4e935442cc..3f16ebcf1d 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -906,7 +906,21 @@ If the associated object is already saved, `fields_for` autogenerates a hidden i ### The Controller -You do not need to write any specific controller code to use nested attributes. Create and update records as you would with a simple form. +As usual you need to +[whitelist the parameters](action_controller_overview.html#strong-parameters) in +the controller before you pass them to the model: + +```ruby +def create + @person = Person.new(person_params) + # ... +end + +private +def person_params + params.require(:person).permit(:name, addresses_attributes: [:id, :kind, :street]) +end +``` ### Removing Objects @@ -937,6 +951,16 @@ If the hash of attributes for an object contains the key `_destroy` with a value <% end %> ``` +Don't forget to update the whitelisted params in your controller to also include +the `_destroy` field: + +```ruby +def person_params + params.require(:person). + permit(:name, addresses_attributes: [:id, :kind, :street, :_destroy]) +end +``` + ### Preventing Empty Records It is often useful to ignore sets of fields that the user has not filled in. You can control this by passing a `:reject_if` proc to `accepts_nested_attributes_for`. This proc will be called with each hash of attributes submitted by the form. If the proc returns `false` then Active Record will not build an associated object for that hash. The example below only tries to build an address if the `kind` attribute is set. diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index faddda0c0a..3881bb1195 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -103,7 +103,7 @@ To verify that you have everything installed correctly, you should be able to ru $ rails --version ``` -If it says something like "Rails 3.2.9", you are ready to continue. +If it says something like "Rails 4.0.0", you are ready to continue. ### Creating the Blog Application diff --git a/guides/source/initialization.md b/guides/source/initialization.md index 8ba5fa4601..412f2faaaa 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -266,7 +266,7 @@ def start url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" - puts "=> Call with -d to detach" unless options[:daemonize] + puts "=> Run `rails server -h` for more startup options" trap(:INT) { exit } puts "=> Ctrl-C to shutdown server" unless options[:daemonize] diff --git a/guides/source/testing.md b/guides/source/testing.md index 7b206f8b4a..70061dc815 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -1,8 +1,7 @@ A Guide to Testing Rails Applications ===================================== -This guide covers built-in mechanisms offered by Rails to test your -application. +This guide covers built-in mechanisms in Rails for testing your application. After reading this guide, you will know: @@ -38,11 +37,11 @@ Rails creates a `test` folder for you as soon as you create a Rails project usin ```bash $ ls -F test - -fixtures/ functional/ integration/ test_helper.rb unit/ +controllers/ helpers/ mailers/ test_helper.rb +fixtures/ integration/ models/ ``` -The `unit` directory is meant to hold tests for your models, the `functional` directory is meant to hold tests for your controllers and the `integration` directory is meant to hold tests that involve any number of controllers interacting. +The `models` directory is meant to hold tests for your models, the `controllers` directory is meant to hold tests for your controllers and the `integration` directory is meant to hold tests that involve any number of controllers interacting. Fixtures are a way of organizing test data; they reside in the `fixtures` folder. @@ -140,10 +139,9 @@ The default test stub in `test/unit/post_test.rb` looks like this: require 'test_helper' class PostTest < ActiveSupport::TestCase - # Replace this with your real tests. - test "the truth" do - assert true - end + # test "the truth" do + # assert true + # end end ``` @@ -224,34 +222,30 @@ TIP: You can see all these rake tasks and their descriptions by running `rake -- ### Running Tests -Running a test is as simple as invoking the file containing the test cases through Ruby: +Running a test is as simple as invoking the file containing the test cases through `rails test` command. ```bash -$ ruby -Itest test/unit/post_test.rb - -Loaded suite models/post_test -Started +$ rails test test/models/post_test.rb . -Finished in 0.023513 seconds. -1 tests, 1 assertions, 0 failures, 0 errors -``` +Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s. -This will run all the test methods from the test case. Note that `test_helper.rb` is in the `test` directory, hence this directory needs to be added to the load path using the `-I` switch. +1 tests, 1 assertions, 0 failures, 0 errors, 0 skips +``` -You can also run a particular test method from the test case by using the `-n` switch with the `test method name`. +You can also run a particular test method from the test case by running the test and using `-n` switch with the `test method name`. ```bash -$ ruby -Itest test/unit/post_test.rb -n test_the_truth - -Loaded suite unit/post_test -Started +$ rails test test/models/post_test.rb -n test_the_truth . -Finished in 0.023513 seconds. -1 tests, 1 assertions, 0 failures, 0 errors +Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s. + +1 tests, 1 assertions, 0 failures, 0 errors, 0 skips ``` +This will run all test methods from the test case. Note that `test_helper.rb` is in the `test` directory, hence this directory needs to be added to the load path using the `-I` switch. + The `.` (dot) above indicates a passing test. When a test fails you see an `F`; when a test throws an error you see an `E` in its place. The last line of the output is the summary. To see how a test failure is reported, you can add a failing test to the `post_test.rb` test case. @@ -266,17 +260,16 @@ end Let us run this newly added test. ```bash -$ ruby -Itest test/unit/post_test.rb -n test_should_not_save_post_without_title -Loaded suite -e -Started +$ rails test test/models/post_test.rb -n test_should_not_save_post_without_title F -Finished in 0.102072 seconds. + +Finished tests in 0.044632s, 22.4054 tests/s, 22.4054 assertions/s. 1) Failure: -test_should_not_save_post_without_title(PostTest) [/test/models/post_test.rb:6]: -<false> is not true. +test_should_not_save_post_without_title(PostTest) [test/models/post_test.rb:6]: +Failed assertion, no message given. -1 tests, 1 assertions, 1 failures, 0 errors +1 tests, 1 assertions, 1 failures, 0 errors, 0 skips ``` In the output, `F` denotes a failure. You can see the corresponding trace shown under `1)` along with the name of the failing test. The next few lines contain the stack trace followed by a message which mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable, every assertion provides an optional message parameter, as shown here: @@ -292,9 +285,8 @@ Running this test shows the friendlier assertion message: ```bash 1) Failure: -test_should_not_save_post_without_title(PostTest) [/test/models/post_test.rb:6]: -Saved the post without a title. -<false> is not true. +test_should_not_save_post_without_title(PostTest) [test/models/post_test.rb:6]: +Saved the post without a title ``` Now to get this test to pass we can add a model level validation for the _title_ field. @@ -308,13 +300,12 @@ end Now the test should pass. Let us verify by running the test again: ```bash -$ ruby -Itest test/unit/post_test.rb -n test_should_not_save_post_without_title -Loaded suite unit/post_test -Started +$ rails test test/models/post_test.rb -n test_should_not_save_post_without_title . -Finished in 0.193608 seconds. -1 tests, 1 assertions, 0 failures, 0 errors +Finished tests in 0.047721s, 20.9551 tests/s, 20.9551 assertions/s. + +1 tests, 1 assertions, 0 failures, 0 errors, 0 skips ``` Now, if you noticed, we first wrote a test which fails for a desired functionality, then we wrote some code which adds the functionality and finally we ensured that our test passes. This approach to software development is referred to as _Test-Driven Development_ (TDD). @@ -334,18 +325,17 @@ end Now you can see even more output in the console from running the tests: ```bash -$ ruby -Itest test/unit/post_test.rb -n test_should_report_error -Loaded suite -e -Started +$ rails test test/models/post_test.rb -n test_should_report_error E -Finished in 0.082603 seconds. + +Finished tests in 0.030974s, 32.2851 tests/s, 0.0000 assertions/s. 1) Error: test_should_report_error(PostTest): -NameError: undefined local variable or method `some_undefined_variable' for #<PostTest:0x249d354> - /test/models/post_test.rb:6:in `test_should_report_error' +NameError: undefined local variable or method `some_undefined_variable' for #<PostTest:0x007fe32e24afe0> + test/models/post_test.rb:10:in `block in <class:PostTest>' -1 tests, 0 assertions, 0 failures, 1 errors +1 tests, 0 assertions, 0 failures, 1 errors, 0 skips ``` Notice the 'E' in the output. It denotes a test with error. @@ -511,6 +501,21 @@ You also have access to three instance variables in your functional tests: * `@request` - The request * `@response` - The response +### Setting Headers and CGI variables + +Headers and cgi variables can be set directly on the `@request` +instance variable: + +```ruby +# setting a HTTP Header +@request.headers["Accepts"] = "text/plain, text/html" +get :index # simulate the request with custom header + +# setting a CGI variable +@request.headers["HTTP_REFERER"] = "http://example.com/home" +post :create # simulate the request with custom env variable +``` + ### Testing Templates and Layouts If you want to make sure that the response rendered the correct template and layout, you can use the `assert_template` @@ -642,12 +647,9 @@ Here's what a freshly-generated integration test looks like: require 'test_helper' class UserFlowsTest < ActionDispatch::IntegrationTest - fixtures :all - - # Replace this with your real tests. - test "the truth" do - assert true - end + # test "the truth" do + # assert true + # end end ``` @@ -755,23 +757,28 @@ end Rake Tasks for Running your Tests --------------------------------- -You don't need to set up and run your tests by hand on a test-by-test basis. Rails comes with a number of rake tasks to help in testing. The table below lists all rake tasks that come along in the default Rakefile when you initiate a Rails project. +You don't need to set up and run your tests by hand on a test-by-test basis. Rails comes with a number of commands to help in testing. The table below lists all commands that come along in the default Rakefile when you initiate a Rails project. + +| Tasks | Description | +| ------------------------ | ----------- | +| `rails test` | Runs all unit, functional and integration tests. You can also simply run `rails test` as Rails will run all the tests by default| +| `rails test controllers` | Runs all the controller tests from `test/controllers`| +| `rails test functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`| +| `rails test helpers` | Runs all the helper tests from `test/helpers`| +| `rails test integration` | Runs all the integration tests from `test/integration`| +| `rails test mailers` | Runs all the mailer tests from `test/mailers`| +| `rails test models` | Runs all the model tests from `test/models`| +| `rails test units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`| -| Tasks | Description | -| ------------------------------- | ----------- | -| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.| -| `rake test:controllers` | Runs all the controller tests from `test/controllers`| -| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`| -| `rake test:helpers` | Runs all the helper tests from `test/helpers`| -| `rake test:integration` | Runs all the integration tests from `test/integration`| -| `rake test:mailers` | Runs all the mailer tests from `test/mailers`| -| `rake test:models` | Runs all the model tests from `test/models`| -| `rake test:recent` | Tests recent changes| -| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git| -| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`| +There're also some test commands which you can initiate by running rake tasks: +| Tasks | Description | +| ------------------------ | ----------- | +| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.| +| `rake test:recent` | Tests recent changes| +| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git| -Brief Note About `Test::Unit` +Brief Note About `MiniTest` ----------------------------- Ruby ships with a boat load of libraries. Ruby 1.8 provides `Test::Unit`, a framework for unit testing in Ruby. All the basic assertions discussed above are actually defined in `Test::Unit::Assertions`. The class `ActiveSupport::TestCase` which we have been using in our unit and functional tests extends `Test::Unit::TestCase`, allowing @@ -920,19 +927,24 @@ require 'test_helper' class UserMailerTest < ActionMailer::TestCase tests UserMailer test "invite" do - @expected.from = 'me@example.com' - @expected.to = 'friend@example.com' - @expected.subject = "You have been invited by #{@expected.from}" - @expected.body = read_fixture('invite') - @expected.date = Time.now - - assert_equal @expected.encoded, UserMailer.create_invite('me@example.com', 'friend@example.com', @expected.date).encoded + # Send the email, then test that it got queued + email = UserMailer.create_invite('me@example.com', + 'friend@example.com', Time.now).deliver + assert !ActionMailer::Base.deliveries.empty? + + # Test the body of the sent email contains what we expect it to + assert_equal ['me@example.com'], email.from + assert_equal ['friend@example.com'], email.to + assert_equal 'You have been invited by me@example.com', email.subject + assert_equal read_fixture('invite').join, email.body.to_s end - end ``` -In this test, `@expected` is an instance of `TMail::Mail` that you can use in your tests. It is defined in `ActionMailer::TestCase`. The test above uses `@expected` to construct an email, which it then asserts with email created by the custom mailer. The `invite` fixture is the body of the email and is used as the sample content to assert against. The helper `read_fixture` is used to read in the content from this file. +In the test we send the email and store the returned object in the `email` +variable. We then ensure that it was sent (the first assert), then, in the +second batch of assertions, we ensure that the email does indeed contain what we +expect. The helper `read_fixture` is used to read in the content from this file. Here's the content of the `invite` fixture: @@ -944,9 +956,17 @@ You have been invited. Cheers! ``` -This is the right time to understand a little more about writing tests for your mailers. The line `ActionMailer::Base.delivery_method = :test` in `config/environments/test.rb` sets the delivery method to test mode so that email will not actually be delivered (useful to avoid spamming your users while testing) but instead it will be appended to an array (`ActionMailer::Base.deliveries`). +This is the right time to understand a little more about writing tests for your +mailers. The line `ActionMailer::Base.delivery_method = :test` in +`config/environments/test.rb` sets the delivery method to test mode so that +email will not actually be delivered (useful to avoid spamming your users while +testing) but instead it will be appended to an array +(`ActionMailer::Base.deliveries`). -This way, emails are not actually sent, simply constructed. The precise content of the email can then be checked against what is expected, as in the example above. +NOTE: The `ActionMailer::Base.deliveries` array is only reset automatically in +`ActionMailer::TestCase` tests. If you want to have a clean slate outside Action +Mailer tests, you can reset it manually with: +`ActionMailer::Base.deliveries.clear` ### Functional Testing diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 62e2624434..385aa3c51b 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -93,7 +93,7 @@ Rails 4.0 extracted Active Resource to its own gem. If you still need the featur * Rails 4.0 has changed how errors attach with the `ActiveModel::Validations::ConfirmationValidator`. Now when confirmation validations fail, the error will be attached to `:#{attribute}_confirmation` instead of `attribute`. -* Rails 4.0 has changed `ActiveModel::Serializers::JSON.include_root_in_json` default value to `false`. Now, Active Model Serializers and Active Record objects have the same default behavior. This means that you can comment or remove the following option in the `config/initializers/wrap_parameters.rb` file: +* Rails 4.0 has changed `ActiveModel::Serializers::JSON.include_root_in_json` default value to `false`. Now, Active Model Serializers and Active Record objects have the same default behaviour. This means that you can comment or remove the following option in the `config/initializers/wrap_parameters.rb` file: ```ruby # Disable root element in JSON by default. @@ -104,7 +104,17 @@ Rails 4.0 extracted Active Resource to its own gem. If you still need the featur ### Action Pack -* Rails 4.0 introduces a new `UpgradeSignatureToEncryptionCookieStore` cookie store. This is useful for upgrading apps using the old default `CookieStore` to the new default `EncryptedCookieStore`. To use this transitional cookie store, you'll want to leave your existing `secret_token` in place, add a new `secret_key_base`, and change your `session_store` like so: +* Rails 4.0 introduces `ActiveSupport::KeyGenerator` and uses this as a base from which to generate and verify signed cookies (among other things). Existing signed cookies generated with Rails 3.x will be transparently upgraded if you leave your existing `secret_token` in place and add the new `secret_key_base`. + +```ruby + # config/initializers/secret_token.rb + Myapp::Application.config.secret_token = 'existing secret token' + Myapp::Application.config.secret_key_base = 'new secret key base' +``` + +Please note that you should wait to set `secret_key_base` until you have 100% of your userbase on Rails 4.x and are reasonably sure you will not need to rollback to Rails 3.x. This is because cookies signed based on the new `secret_key_base` in Rails 4.x are not backwards compatible with Rails 3.x. You are free to leave your existing `secret_token` in place, not set the new `secret_key_base`, and ignore the deprecation warnings until you are reasonably sure that your upgrade is otherwise complete. + +* Rails 4.0 introduces a new `UpgradeSignatureToEncryptionCookieStore` cookie store. This is useful for upgrading apps using the old default `CookieStore` to the new default `EncryptedCookieStore` which leverages the new `ActiveSupport::KeyGenerator`. To use this transitional cookie store, you'll want to leave your existing `secret_token` in place, add a new `secret_key_base`, and change your `session_store` like so: ```ruby # config/initializers/session_store.rb @@ -129,6 +139,23 @@ Rails 4.0 extracted Active Resource to its own gem. If you still need the featur * Rails 4.0 changed how `assert_generates`, `assert_recognizes`, and `assert_routing` work. Now all these assertions raise `Assertion` instead of `ActionController::RoutingError`. +* Rails 4.0 raises an `ArgumentError` if clashing named routes are defined. This can be triggered by explicitly defined named routes or by the `resources` method. Here are two examples that clash with routes named `example_path`: + +```ruby + get 'one' => 'test#example', as: :example + get 'two' => 'test#example', as: :example +``` + +```ruby + resources :examples + get 'clashing/:id' => 'test#example', as: :example +``` + +In the first case, you can simply avoid using the same name for multiple +routes. In the second, you can use the `only` or `except` options provided by +the `resources` method to restrict the routes created as detailed in the +[Routing Guide](routing.html#restricting-the-routes-created). + * Rails 4.0 also changed the way unicode character routes are drawn. Now you can draw unicode character routes directly. If you already draw such routes, you must change them, for example: ```ruby @@ -310,7 +337,7 @@ config.assets.debug = true Again, most of the changes below are for the asset pipeline. You can read more about these in the [Asset Pipeline](asset_pipeline.html) guide. ```ruby -# Compress JavaScript and CSS +# Compress JavaScripts and CSS config.assets.compress = true # Don't fallback to assets pipeline if a precompiled asset is missed |