railties 3.0.0.beta3 → 3.0.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/README +118 -123
- data/guides/source/3_0_release_notes.textile +13 -11
- data/guides/source/action_controller_overview.textile +2 -2
- data/guides/source/action_mailer_basics.textile +70 -26
- data/guides/source/action_view_overview.textile +1 -1
- data/guides/source/active_record_basics.textile +9 -1
- data/guides/source/active_record_querying.textile +2 -2
- data/guides/source/active_support_core_extensions.textile +377 -9
- data/guides/source/activerecord_validations_callbacks.textile +98 -55
- data/guides/source/association_basics.textile +1 -1
- data/guides/source/caching_with_rails.textile +1 -1
- data/guides/source/command_line.textile +23 -23
- data/guides/source/configuring.textile +1 -3
- data/guides/source/contribute.textile +27 -28
- data/guides/source/credits.html.erb +4 -4
- data/guides/source/debugging_rails_applications.textile +2 -2
- data/guides/source/form_helpers.textile +7 -6
- data/guides/source/generators.textile +19 -29
- data/guides/source/getting_started.textile +106 -49
- data/guides/source/i18n.textile +27 -27
- data/guides/source/index.html.erb +18 -8
- data/guides/source/initialization.textile +140 -514
- data/guides/source/layout.html.erb +6 -4
- data/guides/source/layouts_and_rendering.textile +5 -5
- data/guides/source/migrations.textile +7 -3
- data/guides/source/nested_model_forms.textile +2 -2
- data/guides/source/performance_testing.textile +11 -12
- data/guides/source/plugins.textile +30 -30
- data/guides/source/rails_application_templates.textile +3 -3
- data/guides/source/rails_on_rack.textile +3 -66
- data/guides/source/routing.textile +10 -4
- data/guides/source/security.textile +1 -1
- data/guides/source/testing.textile +55 -52
- data/guides/w3c_validator.rb +67 -0
- data/lib/rails.rb +1 -0
- data/lib/rails/application.rb +49 -13
- data/lib/rails/application/bootstrap.rb +7 -6
- data/lib/rails/application/configuration.rb +24 -47
- data/lib/rails/application/finisher.rb +8 -3
- data/lib/rails/backtrace_cleaner.rb +11 -12
- data/lib/rails/commands.rb +54 -54
- data/lib/rails/commands/application.rb +7 -2
- data/lib/rails/commands/{performance/benchmarker.rb → benchmarker.rb} +0 -0
- data/lib/rails/commands/dbconsole.rb +4 -3
- data/lib/rails/commands/destroy.rb +1 -0
- data/lib/rails/commands/generate.rb +1 -0
- data/lib/rails/commands/{performance/profiler.rb → profiler.rb} +0 -0
- data/lib/rails/commands/runner.rb +4 -2
- data/lib/rails/configuration.rb +36 -0
- data/lib/rails/engine.rb +24 -24
- data/lib/rails/engine/configuration.rb +0 -1
- data/lib/rails/generators.rb +48 -10
- data/lib/rails/generators/actions.rb +5 -3
- data/lib/rails/generators/base.rb +23 -17
- data/lib/rails/generators/erb/scaffold/templates/_form.html.erb +9 -8
- data/lib/rails/generators/erb/scaffold/templates/show.html.erb +1 -1
- data/lib/rails/generators/generated_attribute.rb +7 -6
- data/lib/rails/generators/rails/app/USAGE +2 -2
- data/lib/rails/generators/rails/app/app_generator.rb +242 -97
- data/lib/rails/generators/rails/app/templates/Gemfile +3 -0
- data/lib/rails/generators/rails/app/templates/README +167 -130
- data/lib/rails/generators/rails/app/templates/Rakefile +0 -3
- data/lib/rails/generators/rails/app/templates/config/boot.rb +9 -2
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +5 -5
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +4 -0
- data/lib/rails/generators/rails/app/templates/script/rails +2 -5
- data/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt +1 -3
- data/lib/rails/generators/rails/stylesheets/templates/scaffold.css +5 -9
- data/lib/rails/generators/test_case.rb +12 -0
- data/lib/rails/generators/test_unit/integration/templates/integration_test.rb +1 -1
- data/lib/rails/generators/test_unit/performance/templates/performance_test.rb +1 -1
- data/lib/rails/info.rb +0 -33
- data/lib/rails/log_subscriber.rb +13 -6
- data/lib/rails/rack/logger.rb +4 -3
- data/lib/rails/railtie.rb +4 -0
- data/lib/rails/railtie/configuration.rb +21 -4
- data/lib/rails/tasks/documentation.rake +2 -0
- data/lib/rails/tasks/framework.rake +22 -0
- data/lib/rails/tasks/middleware.rake +1 -1
- data/lib/rails/tasks/routes.rake +5 -1
- data/lib/rails/test_help.rb +3 -1
- data/lib/rails/test_unit/testing.rake +3 -1
- data/lib/rails/version.rb +1 -1
- metadata +12 -19
- data/lib/rails/application/metal_loader.rb +0 -50
- data/lib/rails/dispatcher.rb +0 -24
- data/lib/rails/generators/rails/mailer/USAGE +0 -15
- data/lib/rails/generators/rails/mailer/mailer_generator.rb +0 -14
- data/lib/rails/generators/rails/mailer/templates/mailer.rb +0 -16
- data/lib/rails/generators/rails/metal/USAGE +0 -8
- data/lib/rails/generators/rails/metal/metal_generator.rb +0 -11
- data/lib/rails/generators/rails/metal/templates/metal.rb +0 -12
@@ -698,7 +698,7 @@ The most common entry points are message posts, user comments, and guest books,
|
|
698
698
|
|
699
699
|
XSS attacks work like this: An attacker injects some code, the web application saves it and displays it on a page, later presented to a victim. Most XSS examples simply display an alert box, but it is more powerful than that. XSS can steal the cookie, hijack the session, redirect the victim to a fake website, display advertisements for the benefit of the attacker, change elements on the web site to get confidential information or install malicious software through security holes in the web browser.
|
700
700
|
|
701
|
-
During the second half of 2007, there were 88 vulnerabilities reported in Mozilla browsers, 22 in Safari, 18 in IE, and 12 in Opera. The "Symantec Global Internet Security threat report":http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf also documented 239 browser plug-in vulnerabilities in the last six months of 2007. "Mpack":http://pandalabs.pandasecurity.com/
|
701
|
+
During the second half of 2007, there were 88 vulnerabilities reported in Mozilla browsers, 22 in Safari, 18 in IE, and 12 in Opera. The "Symantec Global Internet Security threat report":http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf also documented 239 browser plug-in vulnerabilities in the last six months of 2007. "Mpack":http://pandalabs.pandasecurity.com/mpack-uncovered/ is a very active and up-to-date attack framework which exploits these vulnerabilities. For criminal hackers, it is very attractive to exploit an SQL-Injection vulnerability in a web application framework and insert malicious code in every textual table column. In April 2008 more than 510,000 sites were hacked like this, among them the British government, United Nations, and many more high targets.
|
702
702
|
|
703
703
|
A relatively new, and unusual, form of entry points are banner advertisements. In earlier 2008, malicious code appeared in banner ads on popular sites, such as MySpace and Excite, according to "Trend Micro":http://blog.trendmicro.com/myspace-excite-and-blick-serve-up-malicious-banner-ads/.
|
704
704
|
|
@@ -12,7 +12,7 @@ endprologue.
|
|
12
12
|
|
13
13
|
h3. Why Write Tests for your Rails Applications?
|
14
14
|
|
15
|
-
* Rails makes it super easy to write your tests. It starts by producing skeleton test code in background while you are creating your models and controllers.
|
15
|
+
* Rails makes it super easy to write your tests. It starts by producing skeleton test code in the background while you are creating your models and controllers.
|
16
16
|
* By simply running your Rails tests you can ensure your code adheres to the desired functionality even after some major code refactoring.
|
17
17
|
* Rails tests can also simulate browser requests and thus you can test your application's response without having to test it through your browser.
|
18
18
|
|
@@ -54,7 +54,7 @@ For good tests, you'll need to give some thought to setting up test data. In Rai
|
|
54
54
|
|
55
55
|
h5. What are Fixtures?
|
56
56
|
|
57
|
-
_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and assume one of two formats: *YAML* or *CSV*. In this guide we will use *YAML
|
57
|
+
_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and assume one of two formats: *YAML* or *CSV*. In this guide, we will use *YAML*, which is the preferred format.
|
58
58
|
|
59
59
|
You'll find fixtures under your +test/fixtures+ directory. When you run +rails generate model+ to create a new model, fixture stubs will be automatically created and placed in this directory.
|
60
60
|
|
@@ -65,7 +65,7 @@ YAML-formatted fixtures are a very human-friendly way to describe your sample da
|
|
65
65
|
Here's a sample YAML fixture file:
|
66
66
|
|
67
67
|
<yaml>
|
68
|
-
#
|
68
|
+
# lo & behold! I am a YAML comment!
|
69
69
|
david:
|
70
70
|
name: David Heinemeier Hansson
|
71
71
|
birthday: 1979-10-15
|
@@ -108,7 +108,7 @@ tag is considered Ruby code. When this fixture is loaded, the +size+ attribute o
|
|
108
108
|
|
109
109
|
h5. Fixtures in Action
|
110
110
|
|
111
|
-
Rails by default automatically loads all fixtures from the
|
111
|
+
Rails by default automatically loads all fixtures from the +test/fixtures+ folder for your unit and functional test. Loading involves three steps:
|
112
112
|
|
113
113
|
* Remove any existing data from the table corresponding to the fixture
|
114
114
|
* Load the fixture data into the table
|
@@ -140,20 +140,20 @@ h3. Unit Testing your Models
|
|
140
140
|
|
141
141
|
In Rails, unit tests are what you write to test your models.
|
142
142
|
|
143
|
-
For this guide we will be using Rails _scaffolding_. It will create the model, a migration, controller and views for the new resource in a single operation. It will also create a full test suite following Rails best practices. I will be using examples from this generated code and
|
143
|
+
For this guide we will be using Rails _scaffolding_. It will create the model, a migration, controller and views for the new resource in a single operation. It will also create a full test suite following Rails best practices. I will be using examples from this generated code and will be supplementing it with additional examples where necessary.
|
144
144
|
|
145
|
-
NOTE: For more information on Rails
|
145
|
+
NOTE: For more information on Rails <i>scaffolding</i>, refer to "Getting Started with Rails":getting_started.html
|
146
146
|
|
147
147
|
When you use +rails generate scaffold+, for a resource among other things it creates a test stub in the +test/unit+ folder:
|
148
148
|
|
149
|
-
<
|
149
|
+
<shell>
|
150
150
|
$ rails generate scaffold post title:string body:text
|
151
151
|
...
|
152
152
|
create app/models/post.rb
|
153
153
|
create test/unit/post_test.rb
|
154
154
|
create test/fixtures/posts.yml
|
155
155
|
...
|
156
|
-
</
|
156
|
+
</shell>
|
157
157
|
|
158
158
|
The default test stub in +test/unit/post_test.rb+ looks like this:
|
159
159
|
|
@@ -174,7 +174,7 @@ A line by line examination of this file will help get you oriented to Rails test
|
|
174
174
|
require 'test_helper'
|
175
175
|
</ruby>
|
176
176
|
|
177
|
-
As you know by now
|
177
|
+
As you know by now, +test_helper.rb+ specifies the default configuration to run our tests. This is included with all the tests, so any methods added to this file are available to all your tests.
|
178
178
|
|
179
179
|
<ruby>
|
180
180
|
class PostTest < ActiveSupport::TestCase
|
@@ -204,16 +204,16 @@ assert true
|
|
204
204
|
|
205
205
|
This line of code is called an _assertion_. An assertion is a line of code that evaluates an object (or expression) for expected results. For example, an assertion can check:
|
206
206
|
|
207
|
-
*
|
207
|
+
* does this value = that value?
|
208
208
|
* is this object nil?
|
209
209
|
* does this line of code throw an exception?
|
210
210
|
* is the user's password greater than 5 characters?
|
211
211
|
|
212
|
-
Every test contains one or more assertions. Only when all the assertions are successful the test
|
212
|
+
Every test contains one or more assertions. Only when all the assertions are successful will the test pass.
|
213
213
|
|
214
214
|
h4. Preparing your Application for Testing
|
215
215
|
|
216
|
-
Before you can run your tests you need to ensure that the test database structure is current. For this you can use the following rake commands:
|
216
|
+
Before you can run your tests, you need to ensure that the test database structure is current. For this you can use the following rake commands:
|
217
217
|
|
218
218
|
<shell>
|
219
219
|
$ rake db:migrate
|
@@ -221,9 +221,9 @@ $ rake db:migrate
|
|
221
221
|
$ rake db:test:load
|
222
222
|
</shell>
|
223
223
|
|
224
|
-
Above +rake db:migrate+ runs any pending migrations on the _development_ environment and updates +db/schema.rb+. +rake db:test:load+ recreates the test database from the current db/schema.rb
|
224
|
+
Above +rake db:migrate+ runs any pending migrations on the _development_ environment and updates +db/schema.rb+. +rake db:test:load+ recreates the test database from the current +db/schema.rb+. On subsequent attempts, it is a good idea to first run +db:test:prepare+, as it first checks for pending migrations and warns you appropriately.
|
225
225
|
|
226
|
-
NOTE: +db:test:prepare+ will fail with an error if db/schema.rb doesn't exists.
|
226
|
+
NOTE: +db:test:prepare+ will fail with an error if +db/schema.rb+ doesn't exists.
|
227
227
|
|
228
228
|
h5. Rake Tasks for Preparing your Application for Testing
|
229
229
|
|
@@ -256,7 +256,7 @@ This will run all the test methods from the test case.
|
|
256
256
|
|
257
257
|
You can also run a particular test method from the test case by using the +-n+ switch with the +test method name+.
|
258
258
|
|
259
|
-
<
|
259
|
+
<shell>
|
260
260
|
$ ruby unit/post_test.rb -n test_truth
|
261
261
|
|
262
262
|
Loaded suite unit/post_test
|
@@ -265,7 +265,7 @@ Started
|
|
265
265
|
Finished in 0.023513 seconds.
|
266
266
|
|
267
267
|
1 tests, 1 assertions, 0 failures, 0 errors
|
268
|
-
</
|
268
|
+
</shell>
|
269
269
|
|
270
270
|
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.
|
271
271
|
|
@@ -280,7 +280,7 @@ end
|
|
280
280
|
|
281
281
|
Let us run this newly added test.
|
282
282
|
|
283
|
-
<
|
283
|
+
<shell>
|
284
284
|
$ ruby unit/post_test.rb -n test_should_not_save_post_without_title
|
285
285
|
Loaded suite -e
|
286
286
|
Started
|
@@ -292,9 +292,9 @@ test_should_not_save_post_without_title(PostTest) [/test/unit/post_test.rb:6]:
|
|
292
292
|
<false> is not true.
|
293
293
|
|
294
294
|
1 tests, 1 assertions, 1 failures, 0 errors
|
295
|
-
</
|
295
|
+
</shell>
|
296
296
|
|
297
|
-
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:
|
297
|
+
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:
|
298
298
|
|
299
299
|
<ruby>
|
300
300
|
test "should not save post without title" do
|
@@ -305,12 +305,12 @@ end
|
|
305
305
|
|
306
306
|
Running this test shows the friendlier assertion message:
|
307
307
|
|
308
|
-
<
|
308
|
+
<shell>
|
309
309
|
1) Failure:
|
310
310
|
test_should_not_save_post_without_title(PostTest) [/test/unit/post_test.rb:6]:
|
311
311
|
Saved the post without a title.
|
312
312
|
<false> is not true.
|
313
|
-
</
|
313
|
+
</shell>
|
314
314
|
|
315
315
|
Now to get this test to pass we can add a model level validation for the _title_ field.
|
316
316
|
|
@@ -322,7 +322,7 @@ end
|
|
322
322
|
|
323
323
|
Now the test should pass. Let us verify by running the test again:
|
324
324
|
|
325
|
-
<
|
325
|
+
<shell>
|
326
326
|
$ ruby unit/post_test.rb -n test_should_not_save_post_without_title
|
327
327
|
Loaded suite unit/post_test
|
328
328
|
Started
|
@@ -330,9 +330,9 @@ Started
|
|
330
330
|
Finished in 0.193608 seconds.
|
331
331
|
|
332
332
|
1 tests, 1 assertions, 0 failures, 0 errors
|
333
|
-
</
|
333
|
+
</shell>
|
334
334
|
|
335
|
-
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).
|
335
|
+
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).
|
336
336
|
|
337
337
|
TIP: Many Rails developers practice _Test-Driven Development_ (TDD). This is an excellent way to build up a test suite that exercises every part of your application. TDD is beyond the scope of this guide, but one place to start is with "15 TDD steps to create a Rails application":http://andrzejonsoftware.blogspot.com/2007/05/15-tdd-steps-to-create-rails.html.
|
338
338
|
|
@@ -348,7 +348,7 @@ end
|
|
348
348
|
|
349
349
|
Now you can see even more output in the console from running the tests:
|
350
350
|
|
351
|
-
<
|
351
|
+
<shell>
|
352
352
|
$ ruby unit/post_test.rb -n test_should_report_error
|
353
353
|
Loaded suite -e
|
354
354
|
Started
|
@@ -361,7 +361,7 @@ NameError: undefined local variable or method `some_undefined_variable' for #<Po
|
|
361
361
|
/test/unit/post_test.rb:6:in `test_should_report_error'
|
362
362
|
|
363
363
|
1 tests, 0 assertions, 0 failures, 1 errors
|
364
|
-
</
|
364
|
+
</shell>
|
365
365
|
|
366
366
|
Notice the 'E' in the output. It denotes a test with error.
|
367
367
|
|
@@ -369,13 +369,13 @@ NOTE: The execution of each test method stops as soon as any error or an asserti
|
|
369
369
|
|
370
370
|
h4. What to Include in Your Unit Tests
|
371
371
|
|
372
|
-
Ideally you would like to include a test for everything which could possibly break. It's a good practice to have at least one test for each of your validations and at least one test for every method in your model.
|
372
|
+
Ideally, you would like to include a test for everything which could possibly break. It's a good practice to have at least one test for each of your validations and at least one test for every method in your model.
|
373
373
|
|
374
374
|
h4. Assertions Available
|
375
375
|
|
376
376
|
By now you've caught a glimpse of some of the assertions that are available. Assertions are the worker bees of testing. They are the ones that actually perform the checks to ensure that things are going as planned.
|
377
377
|
|
378
|
-
There are a bunch of different types of assertions you can use. Here's the complete list of assertions that ship with +test/unit+, the testing library used by Rails. The +[msg]+ parameter is an optional string message you can specify to make your test failure messages clearer. It's not required.
|
378
|
+
There are a bunch of different types of assertions you can use. Here's the complete list of assertions that ship with +test/unit+, the default testing library used by Rails. The +[msg]+ parameter is an optional string message you can specify to make your test failure messages clearer. It's not required.
|
379
379
|
|
380
380
|
|_.Assertion |_.Purpose|
|
381
381
|
|+assert( boolean, [msg] )+ |Ensures that the object/expression is true.|
|
@@ -446,7 +446,7 @@ test "should get index" do
|
|
446
446
|
end
|
447
447
|
</ruby>
|
448
448
|
|
449
|
-
In the +test_should_get_index+ test, Rails simulates a request on the action called index
|
449
|
+
In the +test_should_get_index+ test, Rails simulates a request on the action called +index+, making sure the request was successful and also ensuring that it assigns a valid +posts+ instance variable.
|
450
450
|
|
451
451
|
The +get+ method kicks off the web request and populates the results into the response. It accepts 4 arguments:
|
452
452
|
|
@@ -615,7 +615,7 @@ Here's what a freshly-generated integration test looks like:
|
|
615
615
|
require 'test_helper'
|
616
616
|
|
617
617
|
class UserFlowsTest < ActionController::IntegrationTest
|
618
|
-
|
618
|
+
fixtures :all
|
619
619
|
|
620
620
|
# Replace this with your real tests.
|
621
621
|
test "the truth" do
|
@@ -702,24 +702,24 @@ class UserFlowsTest < ActionController::IntegrationTest
|
|
702
702
|
|
703
703
|
private
|
704
704
|
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
end
|
705
|
+
module CustomDsl
|
706
|
+
def browses_site
|
707
|
+
get "/products/all"
|
708
|
+
assert_response :success
|
709
|
+
assert assigns(:products)
|
711
710
|
end
|
711
|
+
end
|
712
712
|
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
end
|
713
|
+
def login(user)
|
714
|
+
open_session do |sess|
|
715
|
+
sess.extend(CustomDsl)
|
716
|
+
u = users(user)
|
717
|
+
sess.https!
|
718
|
+
sess.post "/login", :username => u.username, :password => u.password
|
719
|
+
assert_equal '/welcome', path
|
720
|
+
sess.https!(false)
|
722
721
|
end
|
722
|
+
end
|
723
723
|
end
|
724
724
|
</ruby>
|
725
725
|
|
@@ -729,12 +729,15 @@ You don't need to set up and run your tests by hand on a test-by-test basis. Rai
|
|
729
729
|
|
730
730
|
|_.Tasks |_.Description|
|
731
731
|
|+rake test+ |Runs all unit, functional and integration tests. You can also simply run +rake+ as the _test_ target is the default.|
|
732
|
-
|+rake test:
|
732
|
+
|+rake test:benchmark+ |Benchmark the performance tests|
|
733
733
|
|+rake test:functionals+ |Runs all the functional tests from +test/functional+|
|
734
734
|
|+rake test:integration+ |Runs all the integration tests from +test/integration+|
|
735
|
+
|+rake test:plugins+ |Run all the plugin tests from +vendor/plugins/*/**/test+ (or specify with +PLUGIN=_name_+)|
|
736
|
+
|+rake test:profile+ |Profile the performance tests|
|
735
737
|
|+rake test:recent+ |Tests recent changes|
|
736
738
|
|+rake test:uncommitted+ |Runs all the tests which are uncommitted. Only supports Subversion|
|
737
|
-
|+rake test:
|
739
|
+
|+rake test:units+ |Runs all the unit tests from +test/unit+|
|
740
|
+
|
738
741
|
|
739
742
|
h3. Brief Note About +Test::Unit+
|
740
743
|
|
@@ -780,7 +783,7 @@ class PostsControllerTest < ActionController::TestCase
|
|
780
783
|
end
|
781
784
|
</ruby>
|
782
785
|
|
783
|
-
Above, the +setup+ method is called before each test and so +@post+ is available for each of the tests. Rails implements +setup+ and +teardown+ as ActiveSupport::Callbacks
|
786
|
+
Above, the +setup+ method is called before each test and so +@post+ is available for each of the tests. Rails implements +setup+ and +teardown+ as +ActiveSupport::Callbacks+. Which essentially means you need not only use +setup+ and +teardown+ as methods in your tests. You could specify them by using:
|
784
787
|
|
785
788
|
* a block
|
786
789
|
* a method (like in the earlier example)
|
@@ -845,9 +848,9 @@ Testing mailer classes requires some specific tools to do a thorough job.
|
|
845
848
|
|
846
849
|
h4. Keeping the Postman in Check
|
847
850
|
|
848
|
-
Your
|
851
|
+
Your mailer classes -- like every other part of your Rails application -- should be tested to ensure that it is working as expected.
|
849
852
|
|
850
|
-
The goals of testing your
|
853
|
+
The goals of testing your mailer classes are to ensure that:
|
851
854
|
|
852
855
|
* emails are being processed (created and sent)
|
853
856
|
* the email content is correct (subject, sender, body, etc)
|
@@ -855,7 +858,7 @@ The goals of testing your +ActionMailer+ classes are to ensure that:
|
|
855
858
|
|
856
859
|
h5. From All Sides
|
857
860
|
|
858
|
-
There are two aspects of testing your mailer, the unit tests and the functional tests. In the unit tests, you run the mailer in isolation with tightly controlled inputs and compare the output to a known value (a fixture
|
861
|
+
There are two aspects of testing your mailer, the unit tests and the functional tests. In the unit tests, you run the mailer in isolation with tightly controlled inputs and compare the output to a known value (a fixture.) In the functional tests you don't so much test the minute details produced by the mailer; instead, we test that our controllers and models are using the mailer in the right way. You test to prove that the right email was sent at the right time.
|
859
862
|
|
860
863
|
h4. Unit Testing
|
861
864
|
|
@@ -907,7 +910,7 @@ However often in unit tests, mails will not actually be sent, simply constructed
|
|
907
910
|
|
908
911
|
h4. Functional Testing
|
909
912
|
|
910
|
-
Functional testing for mailers involves more than just checking that the email body, recipients and so forth are correct. In functional mail tests you call the mail deliver methods and check that the appropriate emails have been appended to the delivery list. It is fairly safe to assume that the deliver methods themselves do their job You are probably more interested in
|
913
|
+
Functional testing for mailers involves more than just checking that the email body, recipients and so forth are correct. In functional mail tests you call the mail deliver methods and check that the appropriate emails have been appended to the delivery list. It is fairly safe to assume that the deliver methods themselves do their job. You are probably more interested in whether your own business logic is sending emails when you expect them to go out. For example, you can check that the invite friend operation is sending an email appropriately:
|
911
914
|
|
912
915
|
<ruby>
|
913
916
|
require 'test_helper'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# ---------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# This script validates the generated guides against the W3C Validator.
|
4
|
+
#
|
5
|
+
# Guides are taken from the output directory, from where all .html files are
|
6
|
+
# submitted to the validator.
|
7
|
+
#
|
8
|
+
# This script is prepared to be launched from the railties directory as a rake task:
|
9
|
+
#
|
10
|
+
# rake validate_guides
|
11
|
+
#
|
12
|
+
# If nothing is specified, all files will be validated, but you can check just
|
13
|
+
# some of them using this environment variable:
|
14
|
+
#
|
15
|
+
# ONLY
|
16
|
+
# Use ONLY if you want to validate only one or a set of guides. Prefixes are
|
17
|
+
# enough:
|
18
|
+
#
|
19
|
+
# # validates only association_basics.html
|
20
|
+
# ONLY=assoc rake validate_guides
|
21
|
+
#
|
22
|
+
# Separate many using commas:
|
23
|
+
#
|
24
|
+
# # validates only
|
25
|
+
# ONLY=assoc,migrations rake validate_guides
|
26
|
+
#
|
27
|
+
# ---------------------------------------------------------------------------
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'w3c_validators'
|
31
|
+
include W3CValidators
|
32
|
+
|
33
|
+
module RailsGuides
|
34
|
+
class Validator
|
35
|
+
|
36
|
+
def validate
|
37
|
+
validator = MarkupValidator.new
|
38
|
+
|
39
|
+
guides_to_validate.each do |f|
|
40
|
+
puts "Validating #{f}"
|
41
|
+
results = validator.validate_file(f)
|
42
|
+
|
43
|
+
if !results.validity
|
44
|
+
puts "#{f} FAILED W3C validation with #{results.errors.size} error(s):"
|
45
|
+
results.errors.each do |error|
|
46
|
+
puts error.to_s
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def guides_to_validate
|
54
|
+
guides = Dir["./guides/output/*.html"]
|
55
|
+
ENV.key?('ONLY') ? select_only(guides) : guides
|
56
|
+
end
|
57
|
+
|
58
|
+
def select_only(guides)
|
59
|
+
prefixes = ENV['ONLY'].split(",").map(&:strip)
|
60
|
+
guides.select do |guide|
|
61
|
+
prefixes.any? {|p| guide.start_with?("./guides/output/#{p}")}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
RailsGuides::Validator.new.validate
|
data/lib/rails.rb
CHANGED
data/lib/rails/application.rb
CHANGED
@@ -12,7 +12,7 @@ module Rails
|
|
12
12
|
# points to it.
|
13
13
|
#
|
14
14
|
# In other words, Rails::Application is Singleton and whenever you are accessing
|
15
|
-
# Rails::Application.config or YourApplication::Application.config, you are actually
|
15
|
+
# Rails::Application.config or YourApplication::Application.config, you are actually
|
16
16
|
# accessing YourApplication::Application.instance.config.
|
17
17
|
#
|
18
18
|
# == Initialization
|
@@ -27,7 +27,7 @@ module Rails
|
|
27
27
|
# Besides providing the same configuration as Rails::Engine and Rails::Railtie,
|
28
28
|
# the application object has several specific configurations, for example
|
29
29
|
# "allow_concurrency", "cache_classes", "consider_all_requests_local", "filter_parameters",
|
30
|
-
# "logger", "
|
30
|
+
# "logger", "reload_engines", "reload_plugins" and so forth.
|
31
31
|
#
|
32
32
|
# Check Rails::Application::Configuration to see them all.
|
33
33
|
#
|
@@ -36,17 +36,15 @@ module Rails
|
|
36
36
|
# The application object is also responsible for holding the routes and reloading routes
|
37
37
|
# whenever the files change in development.
|
38
38
|
#
|
39
|
-
# == Middlewares
|
39
|
+
# == Middlewares
|
40
|
+
#
|
41
|
+
# The Application is also responsible for building the middleware stack.
|
40
42
|
#
|
41
|
-
# The Application is also responsible for building the middleware stack and setting up
|
42
|
-
# both application and engines metals.
|
43
|
-
#
|
44
43
|
class Application < Engine
|
45
44
|
autoload :Bootstrap, 'rails/application/bootstrap'
|
46
45
|
autoload :Configurable, 'rails/application/configurable'
|
47
46
|
autoload :Configuration, 'rails/application/configuration'
|
48
47
|
autoload :Finisher, 'rails/application/finisher'
|
49
|
-
autoload :MetalLoader, 'rails/application/metal_loader'
|
50
48
|
autoload :Railties, 'rails/application/railties'
|
51
49
|
autoload :RoutesReloader, 'rails/application/routes_reloader'
|
52
50
|
|
@@ -69,6 +67,8 @@ module Rails
|
|
69
67
|
raise "You cannot have more than one Rails::Application" if Rails.application
|
70
68
|
super
|
71
69
|
Rails.application = base.instance
|
70
|
+
Rails.application.add_lib_to_load_paths!
|
71
|
+
ActiveSupport.run_load_hooks(:before_configuration, base.instance)
|
72
72
|
end
|
73
73
|
|
74
74
|
def respond_to?(*args)
|
@@ -82,13 +82,23 @@ module Rails
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
delegate :
|
85
|
+
delegate :middleware, :to => :config
|
86
|
+
|
87
|
+
def add_lib_to_load_paths!
|
88
|
+
path = config.root.join('lib').to_s
|
89
|
+
$LOAD_PATH.unshift(path) if File.exists?(path)
|
90
|
+
end
|
86
91
|
|
87
92
|
def require_environment!
|
88
|
-
environment =
|
93
|
+
environment = paths.config.environment.to_a.first
|
89
94
|
require environment if environment
|
90
95
|
end
|
91
96
|
|
97
|
+
def eager_load!
|
98
|
+
railties.all(&:eager_load!)
|
99
|
+
super
|
100
|
+
end
|
101
|
+
|
92
102
|
def routes
|
93
103
|
@routes ||= ActionDispatch::Routing::RouteSet.new
|
94
104
|
end
|
@@ -112,20 +122,23 @@ module Rails
|
|
112
122
|
|
113
123
|
def load_tasks
|
114
124
|
initialize_tasks
|
115
|
-
super
|
116
125
|
railties.all { |r| r.load_tasks }
|
126
|
+
super
|
117
127
|
self
|
118
128
|
end
|
119
129
|
|
120
130
|
def load_generators
|
121
131
|
initialize_generators
|
122
|
-
super
|
123
132
|
railties.all { |r| r.load_generators }
|
133
|
+
super
|
124
134
|
self
|
125
135
|
end
|
126
136
|
|
127
137
|
def app
|
128
|
-
@app ||=
|
138
|
+
@app ||= begin
|
139
|
+
config.middleware = config.middleware.merge_into(default_middleware_stack)
|
140
|
+
config.middleware.build(routes)
|
141
|
+
end
|
129
142
|
end
|
130
143
|
|
131
144
|
def call(env)
|
@@ -149,11 +162,34 @@ module Rails
|
|
149
162
|
|
150
163
|
protected
|
151
164
|
|
165
|
+
def default_middleware_stack
|
166
|
+
ActionDispatch::MiddlewareStack.new.tap do |middleware|
|
167
|
+
middleware.use ::ActionDispatch::Static, paths.public.to_a.first if config.serve_static_assets
|
168
|
+
middleware.use ::Rack::Lock if !config.allow_concurrency
|
169
|
+
middleware.use ::Rack::Runtime
|
170
|
+
middleware.use ::Rails::Rack::Logger
|
171
|
+
middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local if config.action_dispatch.show_exceptions
|
172
|
+
middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
|
173
|
+
middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
|
174
|
+
middleware.use ::ActionDispatch::Callbacks, !config.cache_classes
|
175
|
+
middleware.use ::ActionDispatch::Cookies
|
176
|
+
|
177
|
+
if config.session_store
|
178
|
+
middleware.use config.session_store, config.session_options
|
179
|
+
middleware.use ::ActionDispatch::Flash
|
180
|
+
end
|
181
|
+
|
182
|
+
middleware.use ::ActionDispatch::ParamsParser
|
183
|
+
middleware.use ::Rack::MethodOverride
|
184
|
+
middleware.use ::ActionDispatch::Head
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
152
188
|
def initialize_tasks
|
153
189
|
require "rails/tasks"
|
154
190
|
task :environment do
|
155
191
|
$rails_rake_task = true
|
156
|
-
|
192
|
+
require_environment!
|
157
193
|
end
|
158
194
|
end
|
159
195
|
|