rails 4.0.0.beta1 → 4.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rails might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +78 -0
- data/guides/CHANGELOG.md +3 -0
- data/guides/assets/images/getting_started/unknown_action_create_for_posts.png +0 -0
- data/guides/bug_report_templates/active_record_gem.rb +37 -0
- data/guides/bug_report_templates/active_record_master.rb +48 -0
- data/guides/code/getting_started/Gemfile +16 -11
- data/guides/code/getting_started/app/controllers/comments_controller.rb +2 -2
- data/guides/code/getting_started/app/controllers/posts_controller.rb +2 -2
- data/guides/code/getting_started/config/application.rb +3 -2
- data/guides/code/getting_started/config/initializers/session_store.rb +1 -1
- data/guides/code/getting_started/config/routes.rb +2 -2
- data/guides/code/getting_started/public/404.html +41 -10
- data/guides/code/getting_started/public/422.html +42 -10
- data/guides/code/getting_started/public/500.html +41 -10
- data/guides/rails_guides/markdown/renderer.rb +1 -1
- data/guides/source/2_2_release_notes.md +15 -15
- data/guides/source/4_0_release_notes.md +1 -7
- data/guides/source/action_controller_overview.md +176 -22
- data/guides/source/action_mailer_basics.md +246 -141
- data/guides/source/action_view_overview.md +3 -8
- data/guides/source/active_record_basics.md +98 -95
- data/guides/source/active_record_querying.md +90 -17
- data/guides/source/active_record_validations.md +41 -0
- data/guides/source/active_support_core_extensions.md +23 -3
- data/guides/source/active_support_instrumentation.md +6 -6
- data/guides/source/asset_pipeline.md +1 -1
- data/guides/source/association_basics.md +34 -10
- data/guides/source/caching_with_rails.md +2 -7
- data/guides/source/command_line.md +7 -7
- data/guides/source/configuring.md +3 -3
- data/guides/source/contributing_to_ruby_on_rails.md +38 -5
- data/guides/source/credits.html.erb +1 -1
- data/guides/source/debugging_rails_applications.md +19 -22
- data/guides/source/development_dependencies_install.md +2 -2
- data/guides/source/documents.yaml +5 -1
- data/guides/source/engines.md +21 -16
- data/guides/source/form_helpers.md +28 -7
- data/guides/source/generators.md +2 -2
- data/guides/source/getting_started.md +14 -13
- data/guides/source/i18n.md +22 -0
- data/guides/source/initialization.md +1 -1
- data/guides/source/layouts_and_rendering.md +60 -4
- data/guides/source/migrations.md +27 -2
- data/guides/source/rails_application_templates.md +11 -11
- data/guides/source/rails_on_rack.md +9 -6
- data/guides/source/routing.md +19 -3
- data/guides/source/ruby_on_rails_guides_guidelines.md +1 -1
- data/guides/source/security.md +2 -2
- data/guides/source/testing.md +106 -85
- data/guides/source/upgrading_ruby_on_rails.md +112 -9
- data/guides/source/working_with_javascript_in_rails.md +1 -0
- metadata +17 -16
- data/README.rdoc +0 -77
- data/guides/code/getting_started/app/assets/images/rails.png +0 -0
@@ -266,7 +266,7 @@ def start
|
|
266
266
|
url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}"
|
267
267
|
puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
|
268
268
|
puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}"
|
269
|
-
puts "=>
|
269
|
+
puts "=> Run `rails server -h` for more startup options"
|
270
270
|
trap(:INT) { exit }
|
271
271
|
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
|
272
272
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Layouts and Rendering in Rails
|
2
2
|
==============================
|
3
3
|
|
4
|
-
This guide covers the basic layout features of Action Controller and Action View.
|
4
|
+
This guide covers the basic layout features of Action Controller and Action View.
|
5
5
|
|
6
6
|
After reading this guide, you will know:
|
7
7
|
|
@@ -319,7 +319,62 @@ render status: 500
|
|
319
319
|
render status: :forbidden
|
320
320
|
```
|
321
321
|
|
322
|
-
Rails understands both numeric and
|
322
|
+
Rails understands both numeric status codes and the corresponding symbols shown below:
|
323
|
+
|
324
|
+
| HTTP Status Code | Symbol |
|
325
|
+
| ---------------- | -------------------------------- |
|
326
|
+
| 100 | :continue |
|
327
|
+
| 101 | :switching_protocols |
|
328
|
+
| 102 | :processing |
|
329
|
+
| 200 | :ok |
|
330
|
+
| 201 | :created |
|
331
|
+
| 202 | :accepted |
|
332
|
+
| 203 | :non_authoritative_information |
|
333
|
+
| 204 | :no_content |
|
334
|
+
| 205 | :reset_content |
|
335
|
+
| 206 | :partial_content |
|
336
|
+
| 207 | :multi_status |
|
337
|
+
| 226 | :im_used |
|
338
|
+
| 300 | :multiple_choices |
|
339
|
+
| 301 | :moved_permanently |
|
340
|
+
| 302 | :found |
|
341
|
+
| 303 | :see_other |
|
342
|
+
| 304 | :not_modified |
|
343
|
+
| 305 | :use_proxy |
|
344
|
+
| 306 | :reserved |
|
345
|
+
| 307 | :temporary_redirect |
|
346
|
+
| 400 | :bad_request |
|
347
|
+
| 401 | :unauthorized |
|
348
|
+
| 402 | :payment_required |
|
349
|
+
| 403 | :forbidden |
|
350
|
+
| 404 | :not_found |
|
351
|
+
| 405 | :method_not_allowed |
|
352
|
+
| 406 | :not_acceptable |
|
353
|
+
| 407 | :proxy_authentication_required |
|
354
|
+
| 408 | :request_timeout |
|
355
|
+
| 409 | :conflict |
|
356
|
+
| 410 | :gone |
|
357
|
+
| 411 | :length_required |
|
358
|
+
| 412 | :precondition_failed |
|
359
|
+
| 413 | :request_entity_too_large |
|
360
|
+
| 414 | :request_uri_too_long |
|
361
|
+
| 415 | :unsupported_media_type |
|
362
|
+
| 416 | :requested_range_not_satisfiable |
|
363
|
+
| 417 | :expectation_failed |
|
364
|
+
| 418 | :i'm_a_teapot |
|
365
|
+
| 422 | :unprocessable_entity |
|
366
|
+
| 423 | :locked |
|
367
|
+
| 424 | :failed_dependency |
|
368
|
+
| 426 | :upgrade_required |
|
369
|
+
| 500 | :internal_server_error |
|
370
|
+
| 501 | :not_implemented |
|
371
|
+
| 502 | :bad_gateway |
|
372
|
+
| 503 | :service_unavailable |
|
373
|
+
| 504 | :gateway_timeout |
|
374
|
+
| 505 | :http_version_not_supported |
|
375
|
+
| 506 | :variant_also_negotiates |
|
376
|
+
| 507 | :insufficient_storage |
|
377
|
+
| 510 | :not_extended |
|
323
378
|
|
324
379
|
##### The `:location` Option
|
325
380
|
|
@@ -363,7 +418,7 @@ You can use a symbol to defer the choice of layout until a request is processed:
|
|
363
418
|
|
364
419
|
```ruby
|
365
420
|
class ProductsController < ApplicationController
|
366
|
-
layout
|
421
|
+
layout :products_layout
|
367
422
|
|
368
423
|
def show
|
369
424
|
@product = Product.find(params[:id])
|
@@ -568,7 +623,8 @@ def show
|
|
568
623
|
@book = Book.find_by_id(params[:id])
|
569
624
|
if @book.nil?
|
570
625
|
@books = Book.all
|
571
|
-
|
626
|
+
flash[:alert] = "Your book was not found"
|
627
|
+
render "index"
|
572
628
|
end
|
573
629
|
end
|
574
630
|
```
|
data/guides/source/migrations.md
CHANGED
@@ -61,6 +61,10 @@ migrations are wrapped in a transaction. If the database does not support this
|
|
61
61
|
then when a migration fails the parts of it that succeeded will not be rolled
|
62
62
|
back. You will have to rollback the changes that were made by hand.
|
63
63
|
|
64
|
+
NOTE: There are certain queries that can't run inside a transaction. If your
|
65
|
+
adapter supports DDL transactions you can use `disable_ddl_transaction!` to
|
66
|
+
disable them for a single migration.
|
67
|
+
|
64
68
|
If you wish for a migration to do something that Active Record doesn't know how
|
65
69
|
to reverse, you can use `reversible`:
|
66
70
|
|
@@ -179,6 +183,27 @@ class AddDetailsToProducts < ActiveRecord::Migration
|
|
179
183
|
end
|
180
184
|
```
|
181
185
|
|
186
|
+
If the migration name is of the form "CreateXXX" and is
|
187
|
+
followed by a list of column names and types then a migration creating the table
|
188
|
+
XXX with the columns listed will be generated. For example:
|
189
|
+
|
190
|
+
```bash
|
191
|
+
$ rails generate migration CreateProducts name:string part_number:string
|
192
|
+
```
|
193
|
+
|
194
|
+
generates
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
class CreateProducts < ActiveRecord::Migration
|
198
|
+
def change
|
199
|
+
create_table :products do |t|
|
200
|
+
t.string :name
|
201
|
+
t.string :part_number
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
182
207
|
As always, what has been generated for you is just a starting point. You can add
|
183
208
|
or remove from it as you see fit by editing the
|
184
209
|
`db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb` file.
|
@@ -806,7 +831,7 @@ end
|
|
806
831
|
```
|
807
832
|
|
808
833
|
```ruby
|
809
|
-
# app/
|
834
|
+
# app/models/product.rb
|
810
835
|
|
811
836
|
class Product < ActiveRecord::Base
|
812
837
|
validates :flag, presence: true
|
@@ -831,7 +856,7 @@ end
|
|
831
856
|
```
|
832
857
|
|
833
858
|
```ruby
|
834
|
-
# app/
|
859
|
+
# app/models/product.rb
|
835
860
|
|
836
861
|
class Product < ActiveRecord::Base
|
837
862
|
validates :flag, :fuzz, presence: true
|
@@ -13,7 +13,7 @@ After reading this guide, you will know:
|
|
13
13
|
Usage
|
14
14
|
-----
|
15
15
|
|
16
|
-
To apply a template, you need to provide the Rails generator with the location of the template you wish to apply
|
16
|
+
To apply a template, you need to provide the Rails generator with the location of the template you wish to apply using the -m option. This can either be a path to a file or a URL.
|
17
17
|
|
18
18
|
```bash
|
19
19
|
$ rails new blog -m ~/template.rb
|
@@ -30,7 +30,7 @@ $ rake rails:template LOCATION=http://example.com/template.rb
|
|
30
30
|
Template API
|
31
31
|
------------
|
32
32
|
|
33
|
-
Rails templates API is
|
33
|
+
The Rails templates API is easy to understand. Here's an example of a typical Rails template:
|
34
34
|
|
35
35
|
```ruby
|
36
36
|
# template.rb
|
@@ -43,7 +43,7 @@ git add: "."
|
|
43
43
|
git commit: %Q{ -m 'Initial commit' }
|
44
44
|
```
|
45
45
|
|
46
|
-
The following sections
|
46
|
+
The following sections outline the primary methods provided by the API:
|
47
47
|
|
48
48
|
### gem(*args)
|
49
49
|
|
@@ -66,7 +66,7 @@ bundle install
|
|
66
66
|
|
67
67
|
Wraps gem entries inside a group.
|
68
68
|
|
69
|
-
For example, if you want to load `rspec-rails` only in `development` and `test`
|
69
|
+
For example, if you want to load `rspec-rails` only in the `development` and `test` groups:
|
70
70
|
|
71
71
|
```ruby
|
72
72
|
gem_group :development, :test do
|
@@ -100,7 +100,7 @@ A block can be used in place of the `data` argument.
|
|
100
100
|
|
101
101
|
Adds an initializer to the generated application’s `config/initializers` directory.
|
102
102
|
|
103
|
-
|
103
|
+
Let's say you like using `Object#not_nil?` and `Object#not_blank?`:
|
104
104
|
|
105
105
|
```ruby
|
106
106
|
initializer 'bloatlol.rb', <<-CODE
|
@@ -116,9 +116,9 @@ initializer 'bloatlol.rb', <<-CODE
|
|
116
116
|
CODE
|
117
117
|
```
|
118
118
|
|
119
|
-
Similarly `lib()` creates a file in the `lib/` directory and `vendor()` creates a file in the `vendor/` directory.
|
119
|
+
Similarly, `lib()` creates a file in the `lib/` directory and `vendor()` creates a file in the `vendor/` directory.
|
120
120
|
|
121
|
-
There is even `file()`, which accepts a relative path from `Rails.root` and creates all the directories/
|
121
|
+
There is even `file()`, which accepts a relative path from `Rails.root` and creates all the directories/files needed:
|
122
122
|
|
123
123
|
```ruby
|
124
124
|
file 'app/components/foo.rb', <<-CODE
|
@@ -127,7 +127,7 @@ file 'app/components/foo.rb', <<-CODE
|
|
127
127
|
CODE
|
128
128
|
```
|
129
129
|
|
130
|
-
That’ll create `app/components` directory and put `foo.rb` in there.
|
130
|
+
That’ll create the `app/components` directory and put `foo.rb` in there.
|
131
131
|
|
132
132
|
### rakefile(filename, data = nil, &block)
|
133
133
|
|
@@ -179,7 +179,7 @@ rake "db:migrate", env: 'production'
|
|
179
179
|
|
180
180
|
### route(routing_code)
|
181
181
|
|
182
|
-
Adds a routing entry to the `config/routes.rb` file. In
|
182
|
+
Adds a routing entry to the `config/routes.rb` file. In the steps above, we generated a person scaffold and also removed `README.rdoc`. Now, to make `PeopleController#index` the default page for the application:
|
183
183
|
|
184
184
|
```ruby
|
185
185
|
route "root to: 'person#index'"
|
@@ -197,7 +197,7 @@ end
|
|
197
197
|
|
198
198
|
### ask(question)
|
199
199
|
|
200
|
-
`ask()` gives you a chance to get some feedback from the user and use it in your templates.
|
200
|
+
`ask()` gives you a chance to get some feedback from the user and use it in your templates. Let's say you want your user to name the new shiny library you’re adding:
|
201
201
|
|
202
202
|
```ruby
|
203
203
|
lib_name = ask("What do you want to call the shiny library ?")
|
@@ -211,7 +211,7 @@ CODE
|
|
211
211
|
|
212
212
|
### yes?(question) or no?(question)
|
213
213
|
|
214
|
-
These methods let you ask questions from templates and decide the flow based on the user’s answer.
|
214
|
+
These methods let you ask questions from templates and decide the flow based on the user’s answer. Let's say you want to freeze rails only if the user wants to:
|
215
215
|
|
216
216
|
```ruby
|
217
217
|
rake("rails:freeze:gems") if yes?("Freeze rails gems?")
|
@@ -28,7 +28,10 @@ Rails on Rack
|
|
28
28
|
|
29
29
|
### Rails Application's Rack Object
|
30
30
|
|
31
|
-
`ApplicationName::Application` is the primary Rack application object of a Rails
|
31
|
+
`ApplicationName::Application` is the primary Rack application object of a Rails
|
32
|
+
application. Any Rack compliant web server should be using
|
33
|
+
`ApplicationName::Application` object to serve a Rails
|
34
|
+
application. `Rails.application` refers to the same application object.
|
32
35
|
|
33
36
|
### `rails server`
|
34
37
|
|
@@ -79,11 +82,11 @@ To use `rackup` instead of Rails' `rails server`, you can put the following insi
|
|
79
82
|
|
80
83
|
```ruby
|
81
84
|
# Rails.root/config.ru
|
82
|
-
require
|
85
|
+
require ::File.expand_path('../config/environment', __FILE__)
|
83
86
|
|
84
87
|
use Rack::Debugger
|
85
88
|
use Rack::ContentLength
|
86
|
-
run
|
89
|
+
run Rails.application
|
87
90
|
```
|
88
91
|
|
89
92
|
And start the server:
|
@@ -101,7 +104,7 @@ $ rackup --help
|
|
101
104
|
Action Dispatcher Middleware Stack
|
102
105
|
----------------------------------
|
103
106
|
|
104
|
-
Many of Action
|
107
|
+
Many of Action Dispatcher's internal components are implemented as Rack middlewares. `Rails::Application` uses `ActionDispatch::MiddlewareStack` to combine various internal and external middlewares to form a complete Rails Rack application.
|
105
108
|
|
106
109
|
NOTE: `ActionDispatch::MiddlewareStack` is Rails equivalent of `Rack::Builder`, but built for better flexibility and more features to meet Rails' requirements.
|
107
110
|
|
@@ -324,7 +327,7 @@ config.middleware.clear
|
|
324
327
|
```ruby
|
325
328
|
# config.ru
|
326
329
|
use MyOwnStackFromScratch
|
327
|
-
run
|
330
|
+
run Rails.application
|
328
331
|
```
|
329
332
|
|
330
333
|
Resources
|
@@ -332,7 +335,7 @@ Resources
|
|
332
335
|
|
333
336
|
### Learning Rack
|
334
337
|
|
335
|
-
* [Official Rack Website](http://rack.github.
|
338
|
+
* [Official Rack Website](http://rack.github.io)
|
336
339
|
* [Introducing Rack](http://chneukirchen.org/blog/archive/2007/02/introducing-rack.html)
|
337
340
|
* [Ruby on Rack #1 - Hello Rack!](http://m.onkey.org/ruby-on-rack-1-hello-rack)
|
338
341
|
* [Ruby on Rack #2 - The Builder](http://m.onkey.org/ruby-on-rack-2-the-builder)
|
data/guides/source/routing.md
CHANGED
@@ -138,6 +138,12 @@ Sometimes, you have a resource that clients always look up without referencing a
|
|
138
138
|
get 'profile', to: 'users#show'
|
139
139
|
```
|
140
140
|
|
141
|
+
Passing a `String` to `match` will expect a `controller#action` format, while passing a `Symbol` will map directly to an action:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
get 'profile', to: :show
|
145
|
+
```
|
146
|
+
|
141
147
|
This resourceful route:
|
142
148
|
|
143
149
|
```ruby
|
@@ -155,7 +161,7 @@ creates six different routes in your application, all mapping to the `Geocoders`
|
|
155
161
|
| PATCH/PUT | /geocoder | update | update the one and only geocoder resource |
|
156
162
|
| DELETE | /geocoder | destroy | delete the geocoder resource |
|
157
163
|
|
158
|
-
NOTE: Because you might want to use the same controller for a singular route (`/account`) and a plural route (`/accounts/45`), singular resources map to plural controllers.
|
164
|
+
NOTE: Because you might want to use the same controller for a singular route (`/account`) and a plural route (`/accounts/45`), singular resources map to plural controllers. So that, for example, `resource :photo` and `resources :photos` creates both singular and plural routes that map to the same controller (`PhotosController`).
|
159
165
|
|
160
166
|
A singular resourceful route generates these helpers:
|
161
167
|
|
@@ -530,7 +536,7 @@ In particular, simple routing makes it very easy to map legacy URLs to new Rails
|
|
530
536
|
|
531
537
|
### Bound Parameters
|
532
538
|
|
533
|
-
When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: `:controller` maps to the name of a controller in your application, and `:action` maps to the name of an action within that controller. For example, consider
|
539
|
+
When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: `:controller` maps to the name of a controller in your application, and `:action` maps to the name of an action within that controller. For example, consider this route:
|
534
540
|
|
535
541
|
```ruby
|
536
542
|
get ':controller(/:action(/:id))'
|
@@ -797,6 +803,16 @@ You should put the `root` route at the top of the file, because it is the most p
|
|
797
803
|
|
798
804
|
NOTE: The `root` route only routes `GET` requests to the action.
|
799
805
|
|
806
|
+
You can also use root inside namespaces and scopes as well. For example:
|
807
|
+
|
808
|
+
```ruby
|
809
|
+
namespace :admin do
|
810
|
+
root to: "admin#index"
|
811
|
+
end
|
812
|
+
|
813
|
+
root to: "home#index"
|
814
|
+
```
|
815
|
+
|
800
816
|
### Unicode character routes
|
801
817
|
|
802
818
|
You can specify unicode character routes directly. For example:
|
@@ -840,7 +856,7 @@ resources :user_permissions, controller: 'admin/user_permissions'
|
|
840
856
|
|
841
857
|
This will route to the `Admin::UserPermissions` controller.
|
842
858
|
|
843
|
-
NOTE: Only the directory notation is supported.
|
859
|
+
NOTE: Only the directory notation is supported. Specifying the
|
844
860
|
controller with ruby constant notation (eg. `:controller =>
|
845
861
|
'Admin::UserPermissions'`) can lead to routing problems and results in
|
846
862
|
a warning.
|
@@ -65,7 +65,7 @@ HTML Guides
|
|
65
65
|
|
66
66
|
### Generation
|
67
67
|
|
68
|
-
To generate all the guides, just `cd` into the
|
68
|
+
To generate all the guides, just `cd` into the `guides` directory, run `bundle install` and execute:
|
69
69
|
|
70
70
|
```
|
71
71
|
bundle exec rake guides:generate
|
data/guides/source/security.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Ruby
|
1
|
+
Ruby on Rails Security Guide
|
2
2
|
============================
|
3
3
|
|
4
4
|
This manual describes common security problems in web applications and how to avoid them with Rails.
|
@@ -432,7 +432,7 @@ Depending on your web application, there may be more ways to hijack the user's a
|
|
432
432
|
|
433
433
|
INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._
|
434
434
|
|
435
|
-
But not only spam robots (bots) are a problem, but also automatic login bots. A popular CAPTCHA API is [reCAPTCHA](http://recaptcha.net/) which displays two distorted images of words from old books. It also adds an angled line, rather than a distorted background and high levels of warping on the text as earlier CAPTCHAs did, because the latter were broken. As a bonus, using reCAPTCHA helps to digitize old books. [ReCAPTCHA](
|
435
|
+
But not only spam robots (bots) are a problem, but also automatic login bots. A popular CAPTCHA API is [reCAPTCHA](http://recaptcha.net/) which displays two distorted images of words from old books. It also adds an angled line, rather than a distorted background and high levels of warping on the text as earlier CAPTCHAs did, because the latter were broken. As a bonus, using reCAPTCHA helps to digitize old books. [ReCAPTCHA](https://github.com/ambethia/recaptcha/) is also a Rails plug-in with the same name as the API.
|
436
436
|
|
437
437
|
You will get two keys from the API, a public and a private key, which you have to put into your Rails environment. After that you can use the recaptcha_tags method in the view, and the verify_recaptcha method in the controller. Verify_recaptcha will return false if the validation fails.
|
438
438
|
The problem with CAPTCHAs is, they are annoying. Additionally, some visually impaired users have found certain kinds of distorted CAPTCHAs difficult to read. The idea of negative CAPTCHAs is not to ask a user to proof that he is human, but reveal that a spam robot is a bot.
|
data/guides/source/testing.md
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
A Guide to Testing Rails Applications
|
2
2
|
=====================================
|
3
3
|
|
4
|
-
This guide covers built-in mechanisms
|
5
|
-
application.
|
4
|
+
This guide covers built-in mechanisms in Rails for testing your application.
|
6
5
|
|
7
6
|
After reading this guide, you will know:
|
8
7
|
|
@@ -38,11 +37,11 @@ Rails creates a `test` folder for you as soon as you create a Rails project usin
|
|
38
37
|
|
39
38
|
```bash
|
40
39
|
$ ls -F test
|
41
|
-
|
42
|
-
fixtures/
|
40
|
+
controllers/ helpers/ mailers/ test_helper.rb
|
41
|
+
fixtures/ integration/ models/
|
43
42
|
```
|
44
43
|
|
45
|
-
The `
|
44
|
+
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.
|
46
45
|
|
47
46
|
Fixtures are a way of organizing test data; they reside in the `fixtures` folder.
|
48
47
|
|
@@ -140,10 +139,9 @@ The default test stub in `test/models/post_test.rb` looks like this:
|
|
140
139
|
require 'test_helper'
|
141
140
|
|
142
141
|
class PostTest < ActiveSupport::TestCase
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
end
|
142
|
+
# test "the truth" do
|
143
|
+
# assert true
|
144
|
+
# end
|
147
145
|
end
|
148
146
|
```
|
149
147
|
|
@@ -224,34 +222,30 @@ TIP: You can see all these rake tasks and their descriptions by running `rake --
|
|
224
222
|
|
225
223
|
### Running Tests
|
226
224
|
|
227
|
-
Running a test is as simple as invoking the file containing the test cases through
|
225
|
+
Running a test is as simple as invoking the file containing the test cases through `rake test` command.
|
228
226
|
|
229
227
|
```bash
|
230
|
-
$
|
231
|
-
|
232
|
-
Loaded suite models/post_test
|
233
|
-
Started
|
228
|
+
$ rake test test/models/post_test.rb
|
234
229
|
.
|
235
|
-
Finished in 0.023513 seconds.
|
236
230
|
|
237
|
-
|
238
|
-
```
|
231
|
+
Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s.
|
239
232
|
|
240
|
-
|
233
|
+
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
|
234
|
+
```
|
241
235
|
|
242
|
-
You can also run a particular test method from the test case by
|
236
|
+
You can also run a particular test method from the test case by running the test and providing the `test method name`.
|
243
237
|
|
244
238
|
```bash
|
245
|
-
$
|
246
|
-
|
247
|
-
Loaded suite models/post_test
|
248
|
-
Started
|
239
|
+
$ rake test test/models/post_test.rb test_the_truth
|
249
240
|
.
|
250
|
-
Finished in 0.023513 seconds.
|
251
241
|
|
252
|
-
|
242
|
+
Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s.
|
243
|
+
|
244
|
+
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
|
253
245
|
```
|
254
246
|
|
247
|
+
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.
|
248
|
+
|
255
249
|
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.
|
256
250
|
|
257
251
|
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
|
|
266
260
|
Let us run this newly added test.
|
267
261
|
|
268
262
|
```bash
|
269
|
-
$
|
270
|
-
Loaded suite -e
|
271
|
-
Started
|
263
|
+
$ rake test test/models/post_test.rb test_should_not_save_post_without_title
|
272
264
|
F
|
273
|
-
|
265
|
+
|
266
|
+
Finished tests in 0.044632s, 22.4054 tests/s, 22.4054 assertions/s.
|
274
267
|
|
275
268
|
1) Failure:
|
276
|
-
test_should_not_save_post_without_title(PostTest) [
|
277
|
-
|
269
|
+
test_should_not_save_post_without_title(PostTest) [test/models/post_test.rb:6]:
|
270
|
+
Failed assertion, no message given.
|
278
271
|
|
279
|
-
1 tests, 1 assertions, 1 failures, 0 errors
|
272
|
+
1 tests, 1 assertions, 1 failures, 0 errors, 0 skips
|
280
273
|
```
|
281
274
|
|
282
275
|
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:
|
|
292
285
|
|
293
286
|
```bash
|
294
287
|
1) Failure:
|
295
|
-
test_should_not_save_post_without_title(PostTest) [
|
296
|
-
Saved the post without a title
|
297
|
-
<false> is not true.
|
288
|
+
test_should_not_save_post_without_title(PostTest) [test/models/post_test.rb:6]:
|
289
|
+
Saved the post without a title
|
298
290
|
```
|
299
291
|
|
300
292
|
Now to get this test to pass we can add a model level validation for the _title_ field.
|
@@ -308,13 +300,12 @@ end
|
|
308
300
|
Now the test should pass. Let us verify by running the test again:
|
309
301
|
|
310
302
|
```bash
|
311
|
-
$
|
312
|
-
Loaded suite unit/post_test
|
313
|
-
Started
|
303
|
+
$ rake test test/models/post_test.rb test_should_not_save_post_without_title
|
314
304
|
.
|
315
|
-
Finished in 0.193608 seconds.
|
316
305
|
|
317
|
-
|
306
|
+
Finished tests in 0.047721s, 20.9551 tests/s, 20.9551 assertions/s.
|
307
|
+
|
308
|
+
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
|
318
309
|
```
|
319
310
|
|
320
311
|
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
|
|
334
325
|
Now you can see even more output in the console from running the tests:
|
335
326
|
|
336
327
|
```bash
|
337
|
-
$
|
338
|
-
Loaded suite -e
|
339
|
-
Started
|
328
|
+
$ rake test test/models/post_test.rb test_should_report_error
|
340
329
|
E
|
341
|
-
|
330
|
+
|
331
|
+
Finished tests in 0.030974s, 32.2851 tests/s, 0.0000 assertions/s.
|
342
332
|
|
343
333
|
1) Error:
|
344
334
|
test_should_report_error(PostTest):
|
345
|
-
NameError: undefined local variable or method `some_undefined_variable' for #<PostTest:
|
346
|
-
|
335
|
+
NameError: undefined local variable or method `some_undefined_variable' for #<PostTest:0x007fe32e24afe0>
|
336
|
+
test/models/post_test.rb:10:in `block in <class:PostTest>'
|
347
337
|
|
348
|
-
1 tests, 0 assertions, 0 failures, 1 errors
|
338
|
+
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
|
349
339
|
```
|
350
340
|
|
351
341
|
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:
|
|
511
501
|
* `@request` - The request
|
512
502
|
* `@response` - The response
|
513
503
|
|
504
|
+
### Setting Headers and CGI variables
|
505
|
+
|
506
|
+
Headers and cgi variables can be set directly on the `@request`
|
507
|
+
instance variable:
|
508
|
+
|
509
|
+
```ruby
|
510
|
+
# setting a HTTP Header
|
511
|
+
@request.headers["Accepts"] = "text/plain, text/html"
|
512
|
+
get :index # simulate the request with custom header
|
513
|
+
|
514
|
+
# setting a CGI variable
|
515
|
+
@request.headers["HTTP_REFERER"] = "http://example.com/home"
|
516
|
+
post :create # simulate the request with custom env variable
|
517
|
+
```
|
518
|
+
|
514
519
|
### Testing Templates and Layouts
|
515
520
|
|
516
521
|
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:
|
|
642
647
|
require 'test_helper'
|
643
648
|
|
644
649
|
class UserFlowsTest < ActionDispatch::IntegrationTest
|
645
|
-
|
646
|
-
|
647
|
-
#
|
648
|
-
test "the truth" do
|
649
|
-
assert true
|
650
|
-
end
|
650
|
+
# test "the truth" do
|
651
|
+
# assert true
|
652
|
+
# end
|
651
653
|
end
|
652
654
|
```
|
653
655
|
|
@@ -688,9 +690,9 @@ class UserFlowsTest < ActionDispatch::IntegrationTest
|
|
688
690
|
get "/login"
|
689
691
|
assert_response :success
|
690
692
|
|
691
|
-
post_via_redirect "/login", username: users(:
|
693
|
+
post_via_redirect "/login", username: users(:david).username, password: users(:david).password
|
692
694
|
assert_equal '/welcome', path
|
693
|
-
assert_equal 'Welcome
|
695
|
+
assert_equal 'Welcome david!', flash[:notice]
|
694
696
|
|
695
697
|
https!(false)
|
696
698
|
get "/posts/all"
|
@@ -712,17 +714,17 @@ class UserFlowsTest < ActionDispatch::IntegrationTest
|
|
712
714
|
|
713
715
|
test "login and browse site" do
|
714
716
|
|
715
|
-
# User
|
716
|
-
|
717
|
+
# User david logs in
|
718
|
+
david = login(:david)
|
717
719
|
# User guest logs in
|
718
720
|
guest = login(:guest)
|
719
721
|
|
720
722
|
# Both are now available in different sessions
|
721
|
-
assert_equal 'Welcome
|
723
|
+
assert_equal 'Welcome david!', david.flash[:notice]
|
722
724
|
assert_equal 'Welcome guest!', guest.flash[:notice]
|
723
725
|
|
724
|
-
# User
|
725
|
-
|
726
|
+
# User david can browse site
|
727
|
+
david.browses_site
|
726
728
|
# User guest can browse site as well
|
727
729
|
guest.browses_site
|
728
730
|
|
@@ -755,23 +757,28 @@ end
|
|
755
757
|
Rake Tasks for Running your Tests
|
756
758
|
---------------------------------
|
757
759
|
|
758
|
-
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
|
760
|
+
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.
|
761
|
+
|
762
|
+
| Tasks | Description |
|
763
|
+
| ------------------------ | ----------- |
|
764
|
+
| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake test` as Rails will run all the tests by default|
|
765
|
+
| `rake test:controllers` | Runs all the controller tests from `test/controllers`|
|
766
|
+
| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`|
|
767
|
+
| `rake test:helpers` | Runs all the helper tests from `test/helpers`|
|
768
|
+
| `rake test:integration` | Runs all the integration tests from `test/integration`|
|
769
|
+
| `rake test:mailers` | Runs all the mailer tests from `test/mailers`|
|
770
|
+
| `rake test:models` | Runs all the model tests from `test/models`|
|
771
|
+
| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`|
|
759
772
|
|
760
|
-
|
761
|
-
| ------------------------------- | ----------- |
|
762
|
-
| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.|
|
763
|
-
| `rake test:controllers` | Runs all the controller tests from `test/controllers`|
|
764
|
-
| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`|
|
765
|
-
| `rake test:helpers` | Runs all the helper tests from `test/helpers`|
|
766
|
-
| `rake test:integration` | Runs all the integration tests from `test/integration`|
|
767
|
-
| `rake test:mailers` | Runs all the mailer tests from `test/mailers`|
|
768
|
-
| `rake test:models` | Runs all the model tests from `test/models`|
|
769
|
-
| `rake test:recent` | Tests recent changes|
|
770
|
-
| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git|
|
771
|
-
| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`|
|
773
|
+
There're also some test commands which you can initiate by running rake tasks:
|
772
774
|
|
775
|
+
| Tasks | Description |
|
776
|
+
| ------------------------ | ----------- |
|
777
|
+
| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.|
|
778
|
+
| `rake test:recent` | Tests recent changes|
|
779
|
+
| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git|
|
773
780
|
|
774
|
-
Brief Note About `
|
781
|
+
Brief Note About `MiniTest`
|
775
782
|
-----------------------------
|
776
783
|
|
777
784
|
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'
|
|
920
927
|
class UserMailerTest < ActionMailer::TestCase
|
921
928
|
tests UserMailer
|
922
929
|
test "invite" do
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
assert_equal
|
930
|
+
# Send the email, then test that it got queued
|
931
|
+
email = UserMailer.create_invite('me@example.com',
|
932
|
+
'friend@example.com', Time.now).deliver
|
933
|
+
assert !ActionMailer::Base.deliveries.empty?
|
934
|
+
|
935
|
+
# Test the body of the sent email contains what we expect it to
|
936
|
+
assert_equal ['me@example.com'], email.from
|
937
|
+
assert_equal ['friend@example.com'], email.to
|
938
|
+
assert_equal 'You have been invited by me@example.com', email.subject
|
939
|
+
assert_equal read_fixture('invite').join, email.body.to_s
|
930
940
|
end
|
931
|
-
|
932
941
|
end
|
933
942
|
```
|
934
943
|
|
935
|
-
In
|
944
|
+
In the test we send the email and store the returned object in the `email`
|
945
|
+
variable. We then ensure that it was sent (the first assert), then, in the
|
946
|
+
second batch of assertions, we ensure that the email does indeed contain what we
|
947
|
+
expect. The helper `read_fixture` is used to read in the content from this file.
|
936
948
|
|
937
949
|
Here's the content of the `invite` fixture:
|
938
950
|
|
@@ -944,9 +956,17 @@ You have been invited.
|
|
944
956
|
Cheers!
|
945
957
|
```
|
946
958
|
|
947
|
-
This is the right time to understand a little more about writing tests for your
|
959
|
+
This is the right time to understand a little more about writing tests for your
|
960
|
+
mailers. The line `ActionMailer::Base.delivery_method = :test` in
|
961
|
+
`config/environments/test.rb` sets the delivery method to test mode so that
|
962
|
+
email will not actually be delivered (useful to avoid spamming your users while
|
963
|
+
testing) but instead it will be appended to an array
|
964
|
+
(`ActionMailer::Base.deliveries`).
|
948
965
|
|
949
|
-
|
966
|
+
NOTE: The `ActionMailer::Base.deliveries` array is only reset automatically in
|
967
|
+
`ActionMailer::TestCase` tests. If you want to have a clean slate outside Action
|
968
|
+
Mailer tests, you can reset it manually with:
|
969
|
+
`ActionMailer::Base.deliveries.clear`
|
950
970
|
|
951
971
|
### Functional Testing
|
952
972
|
|
@@ -977,5 +997,6 @@ The built-in `test/unit` based testing is not the only way to test Rails applica
|
|
977
997
|
* [NullDB](http://avdi.org/projects/nulldb/), a way to speed up testing by avoiding database use.
|
978
998
|
* [Factory Girl](https://github.com/thoughtbot/factory_girl/tree/master), a replacement for fixtures.
|
979
999
|
* [Machinist](https://github.com/notahat/machinist/tree/master), another replacement for fixtures.
|
1000
|
+
* [MiniTest::Spec Rails](https://github.com/metaskills/minitest-spec-rails), use the MiniTest::Spec DSL within your rails tests.
|
980
1001
|
* [Shoulda](http://www.thoughtbot.com/projects/shoulda), an extension to `test/unit` with additional helpers, macros, and assertions.
|
981
1002
|
* [RSpec](http://relishapp.com/rspec), a behavior-driven development framework
|