railties 3.0.20 → 3.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +36 -49
- data/README.rdoc +2 -1
- data/guides/assets/stylesheets/fixes.css +16 -0
- data/guides/rails_guides.rb +2 -2
- data/guides/rails_guides/generator.rb +8 -3
- data/guides/rails_guides/textile_extensions.rb +4 -2
- data/guides/source/2_2_release_notes.textile +3 -3
- data/guides/source/2_3_release_notes.textile +2 -2
- data/guides/source/3_0_release_notes.textile +14 -14
- data/guides/source/action_controller_overview.textile +54 -79
- data/guides/source/action_mailer_basics.textile +39 -9
- data/guides/source/action_view_overview.textile +257 -211
- data/guides/source/active_record_basics.textile +1 -1
- data/guides/source/active_record_querying.textile +217 -27
- data/guides/source/active_record_validations_callbacks.textile +94 -25
- data/guides/source/active_support_core_extensions.textile +109 -77
- data/guides/source/ajax_on_rails.textile +15 -150
- data/guides/source/api_documentation_guidelines.textile +12 -12
- data/guides/source/association_basics.textile +74 -60
- data/guides/source/caching_with_rails.textile +59 -60
- data/guides/source/command_line.textile +46 -47
- data/guides/source/configuring.textile +55 -37
- data/guides/source/contribute.textile +7 -7
- data/guides/source/contributing_to_ruby_on_rails.textile +14 -23
- data/guides/source/credits.html.erb +3 -3
- data/guides/source/debugging_rails_applications.textile +59 -46
- data/guides/source/form_helpers.textile +76 -31
- data/guides/source/generators.textile +39 -40
- data/guides/source/getting_started.textile +73 -94
- data/guides/source/i18n.textile +64 -58
- data/guides/source/index.html.erb +3 -3
- data/guides/source/initialization.textile +634 -3284
- data/guides/source/layout.html.erb +6 -7
- data/guides/source/layouts_and_rendering.textile +59 -60
- data/guides/source/migrations.textile +63 -59
- data/guides/source/nested_model_forms.textile +2 -2
- data/guides/source/performance_testing.textile +16 -16
- data/guides/source/plugins.textile +236 -1280
- data/guides/source/rails_application_templates.textile +37 -29
- data/guides/source/rails_on_rack.textile +4 -9
- data/guides/source/routing.textile +96 -75
- data/guides/source/ruby_on_rails_guides_guidelines.textile +19 -12
- data/guides/source/security.textile +57 -30
- data/guides/source/testing.textile +26 -24
- data/guides/w3c_validator.rb +2 -2
- data/lib/rails.rb +1 -7
- data/lib/rails/application.rb +46 -76
- data/lib/rails/application/bootstrap.rb +6 -11
- data/lib/rails/application/configuration.rb +43 -40
- data/lib/rails/application/finisher.rb +16 -4
- data/lib/rails/application/railties.rb +6 -24
- data/lib/rails/application/routes_reloader.rb +45 -0
- data/lib/rails/backtrace_cleaner.rb +1 -1
- data/lib/rails/cli.rb +7 -5
- data/lib/rails/commands.rb +27 -2
- data/lib/rails/commands/application.rb +14 -1
- data/lib/rails/commands/benchmarker.rb +3 -1
- data/lib/rails/commands/dbconsole.rb +2 -2
- data/lib/rails/commands/destroy.rb +3 -1
- data/lib/rails/commands/generate.rb +3 -1
- data/lib/rails/commands/plugin.rb +2 -7
- data/lib/rails/commands/plugin_new.rb +10 -0
- data/lib/rails/commands/profiler.rb +3 -1
- data/lib/rails/commands/server.rb +4 -0
- data/lib/rails/configuration.rb +8 -81
- data/lib/rails/console/app.rb +2 -2
- data/lib/rails/engine.rb +460 -78
- data/lib/rails/engine/configuration.rb +46 -49
- data/lib/rails/engine/railties.rb +33 -0
- data/lib/rails/generators.rb +11 -5
- data/lib/rails/generators/actions.rb +2 -27
- data/lib/rails/generators/app_base.rb +216 -0
- data/lib/rails/generators/base.rb +3 -2
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb +1 -1
- data/lib/rails/generators/generated_attribute.rb +2 -1
- data/lib/rails/generators/migration.rb +6 -2
- data/lib/rails/generators/named_base.rb +79 -3
- data/lib/rails/generators/rails/app/app_generator.rb +44 -209
- data/lib/rails/generators/rails/app/templates/Gemfile +15 -31
- data/lib/rails/generators/rails/app/templates/README +2 -2
- data/lib/rails/generators/rails/app/templates/Rakefile +1 -1
- data/lib/rails/generators/rails/app/templates/{public → app/assets}/images/rails.png +0 -0
- data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +8 -0
- data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +5 -0
- data/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +4 -4
- data/lib/rails/generators/rails/app/templates/config/application.rb +19 -3
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml +4 -4
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +11 -6
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml +3 -3
- data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +1 -2
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +14 -11
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +12 -0
- data/lib/rails/generators/rails/app/templates/config/locales/en.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/routes.rb +1 -1
- data/lib/rails/generators/rails/app/templates/db/{seeds.rb → seeds.rb.tt} +2 -2
- data/lib/rails/generators/rails/app/templates/public/index.html +10 -8
- data/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/functional/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/integration/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/{test_helper.rb.tt → test_helper.rb} +0 -0
- data/lib/rails/generators/rails/app/templates/test/unit/.empty_directory +0 -0
- data/lib/rails/generators/rails/assets/USAGE +20 -0
- data/lib/rails/generators/rails/assets/assets_generator.rb +39 -0
- data/lib/rails/generators/rails/assets/templates/javascript.js +2 -0
- data/lib/rails/generators/rails/assets/templates/javascript.js.coffee +3 -0
- data/lib/rails/generators/rails/assets/templates/stylesheet.css +4 -0
- data/lib/rails/generators/rails/assets/templates/stylesheet.css.scss +5 -0
- data/lib/rails/generators/rails/controller/controller_generator.rb +1 -1
- data/lib/rails/generators/rails/controller/templates/controller.rb +2 -0
- data/lib/rails/generators/rails/generator/generator_generator.rb +2 -2
- data/lib/rails/generators/rails/generator/templates/templates/.empty_directory +0 -0
- data/lib/rails/generators/rails/helper/templates/helper.rb +2 -0
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +7 -0
- data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +4 -4
- data/lib/rails/generators/rails/plugin_new/USAGE +10 -0
- data/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +303 -0
- data/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +9 -0
- data/lib/rails/generators/rails/plugin_new/templates/Gemfile +11 -0
- data/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE +20 -0
- data/lib/rails/generators/rails/plugin_new/templates/README.rdoc +3 -0
- data/lib/rails/generators/rails/plugin_new/templates/Rakefile +21 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/templates/config/routes.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/gitignore +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +16 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb +10 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +5 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb +12 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +10 -0
- data/lib/rails/generators/rails/resource/resource_generator.rb +2 -2
- data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +20 -1
- data/lib/rails/generators/rails/{stylesheets → scaffold}/templates/scaffold.css +0 -0
- data/lib/rails/generators/rails/scaffold/templates/scaffold.css.scss +58 -0
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +21 -19
- data/lib/rails/generators/resource_helpers.rb +3 -3
- data/lib/rails/generators/test_case.rb +2 -20
- data/lib/rails/generators/test_unit/controller/templates/functional_test.rb +5 -4
- data/lib/rails/generators/test_unit/helper/templates/helper_test.rb +2 -0
- data/lib/rails/generators/test_unit/integration/templates/integration_test.rb +3 -4
- data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb +5 -4
- data/lib/rails/generators/test_unit/model/templates/fixtures.yml +1 -1
- data/lib/rails/generators/test_unit/model/templates/unit_test.rb +5 -4
- data/lib/rails/generators/test_unit/observer/templates/unit_test.rb +5 -4
- data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +3 -4
- data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +7 -5
- data/lib/rails/info.rb +0 -1
- data/lib/rails/paths.rb +119 -65
- data/lib/rails/plugin.rb +18 -19
- data/lib/rails/rack/log_tailer.rb +1 -1
- data/lib/rails/railtie.rb +50 -47
- data/lib/rails/railtie/configurable.rb +20 -10
- data/lib/rails/railtie/configuration.rb +20 -19
- data/lib/rails/source_annotation_extractor.rb +5 -5
- data/lib/rails/tasks.rb +1 -0
- data/lib/rails/tasks/assets.rake +10 -0
- data/lib/rails/tasks/documentation.rake +2 -8
- data/lib/rails/tasks/engine.rake +69 -0
- data/lib/rails/tasks/framework.rake +4 -21
- data/lib/rails/tasks/misc.rake +1 -1
- data/lib/rails/tasks/routes.rake +2 -1
- data/lib/rails/test_help.rb +17 -1
- data/lib/rails/test_unit/railtie.rb +1 -1
- data/lib/rails/test_unit/testing.rake +8 -3
- data/lib/rails/version.rb +3 -3
- metadata +128 -100
- checksums.yaml +0 -7
- data/lib/rails/application/configurable.rb +0 -19
- data/lib/rails/console/sandbox.rb +0 -6
- data/lib/rails/deprecation.rb +0 -41
- data/lib/rails/engine/configurable.rb +0 -25
- data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml +0 -62
- data/lib/rails/generators/rails/app/templates/public/javascripts/application.js +0 -2
- data/lib/rails/generators/rails/app/templates/public/javascripts/controls.js +0 -965
- data/lib/rails/generators/rails/app/templates/public/javascripts/dragdrop.js +0 -974
- data/lib/rails/generators/rails/app/templates/public/javascripts/effects.js +0 -1123
- data/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js +0 -6001
- data/lib/rails/generators/rails/app/templates/public/javascripts/rails.js +0 -202
- data/lib/rails/generators/rails/stylesheets/USAGE +0 -5
- data/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb +0 -9
- data/lib/rails/info_routes.rb +0 -3
@@ -10,20 +10,20 @@ Guides are written in "Textile":http://www.textism.com/tools/textile/. There's c
|
|
10
10
|
|
11
11
|
h3. Prologue
|
12
12
|
|
13
|
-
Each guide should start with motivational text at the top
|
13
|
+
Each guide should start with motivational text at the top (that's the little introduction in the blue area.) The prologue should tell the reader what the guide is about, and what they will learn. See for example the "Routing Guide":routing.html.
|
14
14
|
|
15
15
|
h3. Titles
|
16
16
|
|
17
17
|
The title of every guide uses +h2+, guide sections use +h3+, subsections +h4+, etc.
|
18
18
|
|
19
|
-
Capitalize all words except for internal articles, prepositions,
|
19
|
+
Capitalize all words except for internal articles, prepositions, conjunctions, and forms of the verb to be:
|
20
20
|
|
21
21
|
<plain>
|
22
22
|
h5. Middleware Stack is an Array
|
23
23
|
h5. When are Objects Saved?
|
24
24
|
</plain>
|
25
25
|
|
26
|
-
Use same typography as in regular text:
|
26
|
+
Use the same typography as in regular text:
|
27
27
|
|
28
28
|
<plain>
|
29
29
|
h6. The +:content_type+ Option
|
@@ -42,29 +42,35 @@ Those guidelines apply also to guides.
|
|
42
42
|
|
43
43
|
h3. HTML Generation
|
44
44
|
|
45
|
-
To generate all the guides just cd into the +railties+ directory and execute
|
45
|
+
To generate all the guides, just +cd+ into the +railties+ directory and execute:
|
46
46
|
|
47
47
|
<plain>
|
48
|
-
rake generate_guides
|
48
|
+
bundle exec rake generate_guides
|
49
49
|
</plain>
|
50
50
|
|
51
|
-
You
|
51
|
+
(You may need to run +bundle install+ first to install the required gems.)
|
52
52
|
|
53
53
|
To process +my_guide.textile+ and nothing else use the +ONLY+ environment variable:
|
54
54
|
|
55
55
|
<plain>
|
56
|
-
rake generate_guides ONLY=my_guide
|
56
|
+
bundle exec rake generate_guides ONLY=my_guide
|
57
57
|
</plain>
|
58
58
|
|
59
|
-
|
59
|
+
By default, guides that have not been modified are not processed, so +ONLY+ is rarely needed in practice.
|
60
60
|
|
61
|
-
To force process of
|
61
|
+
To force process of all the guides, pass +ALL=1+.
|
62
62
|
|
63
|
-
It is also recommended that you work with +WARNINGS=1
|
63
|
+
It is also recommended that you work with +WARNINGS=1+. This detects duplicate IDs and warns about broken internal links.
|
64
64
|
|
65
|
-
|
65
|
+
If you want to generate guides in languages other than English, you can keep them in a separate directory under +source+ (eg. <tt>source/es</tt>) and use the +LANGUAGE+ environment variable:
|
66
66
|
|
67
|
-
|
67
|
+
<plain>
|
68
|
+
rake generate_guides LANGUAGE=es
|
69
|
+
</plain>
|
70
|
+
|
71
|
+
h3. HTML Validation
|
72
|
+
|
73
|
+
Please validate the generated HTML with:
|
68
74
|
|
69
75
|
<plain>
|
70
76
|
rake validate_guides
|
@@ -74,4 +80,5 @@ Particularly, titles get an ID generated from their content and this often leads
|
|
74
80
|
|
75
81
|
h3. Changelog
|
76
82
|
|
83
|
+
* March 31, 2011: grammar tweaks by "Josiah Ivey":http://twitter.com/josiahivey
|
77
84
|
* October 5, 2010: ported from the docrails wiki and revised by "Xavier Noria":credits.html#fxn
|
@@ -57,7 +57,11 @@ Many web applications have an authentication system: a user provides a user name
|
|
57
57
|
|
58
58
|
Hence, the cookie serves as temporary authentication for the web application. Everyone who seizes a cookie from someone else, may use the web application as this user – with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures:
|
59
59
|
|
60
|
-
* Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _(highlight)provide a secure connection over SSL_.
|
60
|
+
* Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _(highlight)provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file:
|
61
|
+
|
62
|
+
<ruby>
|
63
|
+
config.force_ssl = true
|
64
|
+
</ruby>
|
61
65
|
|
62
66
|
* Most people don't clear out the cookies after working at a public terminal. So if the last user didn't log out of a web application, you would be able to use it as this user. Provide the user with a _(highlight)log-out button_ in the web application, and _(highlight)make it prominent_.
|
63
67
|
|
@@ -143,7 +147,7 @@ reset_session
|
|
143
147
|
|
144
148
|
If you use the popular RestfulAuthentication plugin for user management, add reset_session to the SessionsController#create action. Note that this removes any value from the session, _(highlight)you have to transfer them to the new session_.
|
145
149
|
|
146
|
-
Another countermeasure is to _(highlight)save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _(highlight)These might change over the course of a session_, so these users
|
150
|
+
Another countermeasure is to _(highlight)save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _(highlight)These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way.
|
147
151
|
|
148
152
|
h4. Session Expiry
|
149
153
|
|
@@ -207,15 +211,7 @@ The HTTP protocol basically provides two main types of requests - GET and POST (
|
|
207
211
|
|
208
212
|
If your web application is RESTful, you might be used to additional HTTP verbs, such as PUT or DELETE. Most of today‘s web browsers, however do not support them - only GET and POST. Rails uses a hidden +_method+ field to handle this barrier.
|
209
213
|
|
210
|
-
_(highlight)
|
211
|
-
|
212
|
-
<ruby>
|
213
|
-
verify :method => :post, :only => [:transfer], :redirect_to => {:action => :list}
|
214
|
-
</ruby>
|
215
|
-
|
216
|
-
With this precaution, the attack from above will not work, because the browser sends a GET request for images, which will not be accepted by the web application.
|
217
|
-
|
218
|
-
But this was only the first step, because _(highlight)POST requests can be sent automatically, too_. Here is an example for a link which displays www.harmless.com as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request.
|
214
|
+
_(highlight)POST requests can be sent automatically, too_. Here is an example for a link which displays www.harmless.com as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request.
|
219
215
|
|
220
216
|
<html>
|
221
217
|
<a href="http://www.harmless.com/" onclick="
|
@@ -234,13 +230,13 @@ Or the attacker places the code into the onmouseover event handler of an image:
|
|
234
230
|
<img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />
|
235
231
|
</html>
|
236
232
|
|
237
|
-
There are many other possibilities, including Ajax to attack the victim in the background.
The
|
233
|
+
There are many other possibilities, including Ajax to attack the victim in the background.
The _(highlight)solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller:
|
238
234
|
|
239
235
|
<ruby>
|
240
236
|
protect_from_forgery :secret => "123456789012345678901234567890..."
|
241
237
|
</ruby>
|
242
238
|
|
243
|
-
This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage.
|
239
|
+
This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. *Note:* In Rails versions prior to 3.0.4, this raised an <tt>ActionController::InvalidAuthenticityToken</tt> error.
|
244
240
|
|
245
241
|
Note that _(highlight)cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form. Read <a href="#cross-site-scripting-xss">more about XSS</a> later.
|
246
242
|
|
@@ -282,7 +278,7 @@ h4. File Uploads
|
|
282
278
|
|
283
279
|
Many web applications allow users to upload files. _(highlight)File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so – one more reason to run web servers, database servers and other programs as a less privileged Unix user.
|
284
280
|
|
285
|
-
When filtering user input file names, _(highlight)don't try to remove malicious parts_. Think of a situation where the web application removes all “../” in a file name and an attacker uses a string such as “....//” - the result will be “../”. It is best to use a whitelist approach, which _(highlight)checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the "attachment_fu plugin":
|
281
|
+
When filtering user input file names, _(highlight)don't try to remove malicious parts_. Think of a situation where the web application removes all “../” in a file name and an attacker uses a string such as “....//” - the result will be “../”. It is best to use a whitelist approach, which _(highlight)checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the "attachment_fu plugin":https://github.com/technoweenie/attachment_fu/tree/master:
|
286
282
|
|
287
283
|
<ruby>
|
288
284
|
def sanitize_filename(filename)
|
@@ -390,7 +386,7 @@ params[:user] # => {:name => “ow3ned”, :admin => true}
|
|
390
386
|
|
391
387
|
So if you create a new user using mass-assignment, it may be too easy to become an administrator.
|
392
388
|
|
393
|
-
Note that this vulnerability is not restricted to database columns. Any setter method, unless explicitly protected, is accessible via the <tt>attributes=</tt> method.
|
389
|
+
Note that this vulnerability is not restricted to database columns. Any setter method, unless explicitly protected, is accessible via the <tt>attributes=</tt> method. In fact, this vulnerability is extended even further with the introduction of nested mass assignment (and nested object forms) in Rails 2.3. The +accepts_nested_attributes_for+ declaration provides us the ability to extend mass assignment to model associations (+has_many+, +has_one+, +has_and_belongs_to_many+). For example:
|
394
390
|
|
395
391
|
<ruby>
|
396
392
|
class Person < ActiveRecord::Base
|
@@ -414,10 +410,17 @@ To avoid this, Rails provides two class methods in your Active Record class to c
|
|
414
410
|
attr_protected :admin
|
415
411
|
</ruby>
|
416
412
|
|
413
|
+
+attr_protected+ also optionally takes a scope option using :as which allows you to define multiple mass-assignment groupings. If no scope is defined then attributes will be added to the default group.
|
414
|
+
|
415
|
+
<ruby>
|
416
|
+
attr_protected :last_login, :as => :admin
|
417
|
+
</ruby>
|
418
|
+
|
417
419
|
A much better way, because it follows the whitelist-principle, is the +attr_accessible+ method. It is the exact opposite of +attr_protected+, because _(highlight)it takes a list of attributes that will be accessible_. All other attributes will be protected. This way you won't forget to protect attributes when adding new ones in the course of development. Here is an example:
|
418
420
|
|
419
421
|
<ruby>
|
420
422
|
attr_accessible :name
|
423
|
+
attr_accessible :name, :is_admin, :as => :admin
|
421
424
|
</ruby>
|
422
425
|
|
423
426
|
If you want to set a protected attribute, you will to have to assign it individually:
|
@@ -430,13 +433,43 @@ params[:user] # => {:name => "ow3ned", :admin => true}
|
|
430
433
|
@user.admin # => true
|
431
434
|
</ruby>
|
432
435
|
|
433
|
-
|
436
|
+
When assigning attributes in Active Record using +attributes=+, or +update_attributes+ the :default scope will be used. To assign attributes using different scopes you should use +assign_attributes+ which accepts an optional :as options parameter. If no :as option is provided then the :default scope will be used. You can also bypass mass-assignment security by using the +:without_protection+ option. Here is an example:
|
434
437
|
|
435
438
|
<ruby>
|
436
|
-
|
439
|
+
@user = User.new
|
440
|
+
|
441
|
+
@user.assign_attributes({ :name => 'Josh', :is_admin => true })
|
442
|
+
@user.name # => Josh
|
443
|
+
@user.is_admin # => false
|
444
|
+
|
445
|
+
@user.assign_attributes({ :name => 'Josh', :is_admin => true }, :as => :admin)
|
446
|
+
@user.name # => Josh
|
447
|
+
@user.is_admin # => true
|
448
|
+
|
449
|
+
@user.assign_attributes({ :name => 'Josh', :is_admin => true }, :without_protection => true)
|
450
|
+
@user.name # => Josh
|
451
|
+
@user.is_admin # => true
|
437
452
|
</ruby>
|
438
453
|
|
439
|
-
|
454
|
+
In a similar way, +new+, +create+ and <tt>create!</tt> methods respect mass-assignment security and accepts either +:as+ or +:without_protection+ options. For example:
|
455
|
+
|
456
|
+
<ruby>
|
457
|
+
@user = User.new({ :name => 'Sebastian', :is_admin => true }, :as => :admin)
|
458
|
+
@user.name # => Sebastian
|
459
|
+
@user.is_admin # => true
|
460
|
+
|
461
|
+
@user = User.create({ :name => 'Sebastian', :is_admin => true }, :without_protection => true)
|
462
|
+
@user.name # => Sebastian
|
463
|
+
@user.is_admin # => true
|
464
|
+
</ruby>
|
465
|
+
|
466
|
+
A more paranoid technique to protect your whole project would be to enforce that all models define their accessible attributes. This can be easily achieved with a very simple application config option of:
|
467
|
+
|
468
|
+
<ruby>
|
469
|
+
config.active_record.whitelist_attributes = true
|
470
|
+
</ruby>
|
471
|
+
|
472
|
+
This will create an empty whitelist of attributes available for mass-assignment for all models in your app. As such, your models will need to explicitly whitelist or blacklist accessible parameters by using an +attr_accessible+ or +attr_protected+ declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to use this application config option; run your tests, and expose each attribute (via +attr_accessible+ or +attr_protected+) as dictated by your failing tests.
|
440
473
|
|
441
474
|
h3. User Management
|
442
475
|
|
@@ -550,7 +583,7 @@ Ruby uses a slightly different approach than many other languages to match the e
|
|
550
583
|
|
551
584
|
<ruby>
|
552
585
|
class File < ActiveRecord::Base
|
553
|
-
|
586
|
+
validates :name, :format => /^[\w\.\-\+]+$/
|
554
587
|
end
|
555
588
|
</ruby>
|
556
589
|
|
@@ -616,7 +649,7 @@ h5(#sql-injection-introduction). Introduction
|
|
616
649
|
SQL injection attacks aim at influencing database queries by manipulating web application parameters. A popular goal of SQL injection attacks is to bypass authorization. Another goal is to carry out data manipulation or reading arbitrary data. Here is an example of how not to use user input data in a query:
|
617
650
|
|
618
651
|
<ruby>
|
619
|
-
Project.
|
652
|
+
Project.all(:conditions => "name = '#{params[:name]}'")
|
620
653
|
</ruby>
|
621
654
|
|
622
655
|
This could be in a search action and the user may enter a project's name that he wants to find. If a malicious user enters ' OR 1 --, the resulting SQL query will be:
|
@@ -632,7 +665,7 @@ h5. Bypassing Authorization
|
|
632
665
|
Usually a web application includes access control. The user enters his login credentials, the web application tries to find the matching record in the users table. The application grants access when it finds a record. However, an attacker may possibly bypass this check with SQL injection. The following shows a typical database query in Rails to find the first record in the users table which matches the login credentials parameters supplied by the user.
|
633
666
|
|
634
667
|
<ruby>
|
635
|
-
User.
|
668
|
+
User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'")
|
636
669
|
</ruby>
|
637
670
|
|
638
671
|
If an attacker enters ' OR '1'='1 as the name, and ' OR '2'>'1 as the password, the resulting SQL query will be:
|
@@ -648,7 +681,7 @@ h5. Unauthorized Reading
|
|
648
681
|
The UNION statement connects two SQL queries and returns the data in one set. An attacker can use it to read arbitrary data from the database. Let's take the example from above:
|
649
682
|
|
650
683
|
<ruby>
|
651
|
-
Project.
|
684
|
+
Project.all(:conditions => "name = '#{params[:name]}'")
|
652
685
|
</ruby>
|
653
686
|
|
654
687
|
And now let's inject another query using the UNION statement:
|
@@ -675,13 +708,13 @@ Ruby on Rails has a built-in filter for special SQL characters, which will escap
|
|
675
708
|
Instead of passing a string to the conditions option, you can pass an array to sanitize tainted strings like this:
|
676
709
|
|
677
710
|
<ruby>
|
678
|
-
Model.
|
711
|
+
Model.first(:conditions => ["login = ? AND password = ?", entered_user_name, entered_password])
|
679
712
|
</ruby>
|
680
713
|
|
681
714
|
As you can see, the first part of the array is an SQL fragment with question marks. The sanitized versions of the variables in the second part of the array replace the question marks. Or you can pass a hash for the same result:
|
682
715
|
|
683
716
|
<ruby>
|
684
|
-
Model.
|
717
|
+
Model.first(:conditions => {:login => entered_user_name, :password => entered_password})
|
685
718
|
</ruby>
|
686
719
|
|
687
720
|
The array or hash form is only available in model instances. You can try +sanitize_sql()+ elsewhere. _(highlight)Make it a habit to think about the security consequences when using an external string in SQL_.
|
@@ -889,12 +922,6 @@ h4. Ajax Injection
|
|
889
922
|
|
890
923
|
If you use the "in_place_editor plugin":http://dev.rubyonrails.org/browser/plugins/in_place_editing, or actions that return a string, rather than rendering a view, _(highlight)you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
|
891
924
|
|
892
|
-
h4. RJS Injection
|
893
|
-
|
894
|
-
-- _Don't forget to escape in JavaScript (RJS) templates, too._
|
895
|
-
|
896
|
-
The RJS API generates blocks of JavaScript code based on Ruby code, thus allowing you to manipulate a view or parts of a view from the server side. <em class="highlight">If you allow user input in RJS templates, do escape it using +escape_javascript()+ within JavaScript functions, and in HTML parts using +h()+</em>. Otherwise an attacker could execute arbitrary JavaScript.
|
897
|
-
|
898
925
|
h4. Command Line Injection
|
899
926
|
|
900
927
|
-- _Use user-supplied command line parameters with caution._
|
@@ -79,9 +79,9 @@ steve:
|
|
79
79
|
|
80
80
|
Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are separated by a blank space. You can place comments in a fixture file by using the # character in the first column.
|
81
81
|
|
82
|
-
h5.
|
82
|
+
h5. ERB'in It Up
|
83
83
|
|
84
|
-
|
84
|
+
ERB allows you to embed ruby code within templates. Both the YAML and CSV fixture formats are pre-processed with ERB when you load fixtures. This allows you to use Ruby to help you generate some sample data.
|
85
85
|
|
86
86
|
<erb>
|
87
87
|
<% earth_size = 20 %>
|
@@ -227,15 +227,15 @@ $ rake db:migrate
|
|
227
227
|
$ rake db:test:load
|
228
228
|
</shell>
|
229
229
|
|
230
|
-
|
230
|
+
The +rake db:migrate+ above runs any pending migrations on the _development_ environment and updates +db/schema.rb+. The +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.
|
231
231
|
|
232
|
-
NOTE: +db:test:prepare+ will fail with an error if +db/schema.rb+ doesn't
|
232
|
+
NOTE: +db:test:prepare+ will fail with an error if +db/schema.rb+ doesn't exist.
|
233
233
|
|
234
234
|
h5. Rake Tasks for Preparing your Application for Testing
|
235
235
|
|
236
236
|
|_.Tasks |_.Description|
|
237
237
|
|+rake db:test:clone+ |Recreate the test database from the current environment's database schema|
|
238
|
-
|+rake db:test:clone_structure+ |Recreate the test
|
238
|
+
|+rake db:test:clone_structure+ |Recreate the test database from the development structure|
|
239
239
|
|+rake db:test:load+ |Recreate the test database from the current +schema.rb+|
|
240
240
|
|+rake db:test:prepare+ |Check for pending migrations and load the test schema|
|
241
241
|
|+rake db:test:purge+ |Empty the test database.|
|
@@ -262,7 +262,7 @@ This will run all the test methods from the test case. Note that +test_helper.rb
|
|
262
262
|
You can also run a particular test method from the test case by using the +-n+ switch with the +test method name+.
|
263
263
|
|
264
264
|
<shell>
|
265
|
-
$ ruby -Itest test/unit/post_test.rb -n
|
265
|
+
$ ruby -Itest test/unit/post_test.rb -n test_the_truth
|
266
266
|
|
267
267
|
Loaded suite unit/post_test
|
268
268
|
Started
|
@@ -321,7 +321,7 @@ Now to get this test to pass we can add a model level validation for the _title_
|
|
321
321
|
|
322
322
|
<ruby>
|
323
323
|
class Post < ActiveRecord::Base
|
324
|
-
|
324
|
+
validates :title, :presence => true
|
325
325
|
end
|
326
326
|
</ruby>
|
327
327
|
|
@@ -391,7 +391,7 @@ There are a bunch of different types of assertions you can use. Here's the compl
|
|
391
391
|
|+assert_nil( obj, [msg] )+ |Ensures that +obj.nil?+ is true.|
|
392
392
|
|+assert_not_nil( obj, [msg] )+ |Ensures that +obj.nil?+ is false.|
|
393
393
|
|+assert_match( regexp, string, [msg] )+ |Ensures that a string matches the regular expression.|
|
394
|
-
|+assert_no_match( regexp, string, [msg] )+ |Ensures that a string doesn't
|
394
|
+
|+assert_no_match( regexp, string, [msg] )+ |Ensures that a string doesn't match the regular expression.|
|
395
395
|
|+assert_in_delta( expecting, actual, delta, [msg] )+ |Ensures that the numbers +expecting+ and +actual+ are within +delta+ of each other.|
|
396
396
|
|+assert_throws( symbol, [msg] ) { block }+ |Ensures that the given block throws the symbol.|
|
397
397
|
|+assert_raise( exception1, exception2, ... ) { block }+ |Ensures that the given block raises one of the given exceptions.|
|
@@ -415,8 +415,8 @@ NOTE: +assert_valid(record)+ has been deprecated. Please use +assert(record.vali
|
|
415
415
|
|
416
416
|
|_.Assertion |_.Purpose|
|
417
417
|
|+assert_valid(record)+ |Ensures that the passed record is valid by Active Record standards and returns any error messages if it is not.|
|
418
|
-
|+assert_difference(expressions, difference = 1, message = nil) {...}+
|
419
|
-
|+assert_no_difference(expressions, message = nil, &block)+
|
418
|
+
|+assert_difference(expressions, difference = 1, message = nil) {...}+ |Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.|
|
419
|
+
|+assert_no_difference(expressions, message = nil, &block)+ |Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.|
|
420
420
|
|+assert_recognizes(expected_options, path, extras={}, message=nil)+ |Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.|
|
421
421
|
|+assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)+ |Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.|
|
422
422
|
|+assert_response(type, message = nil)+ |Asserts that the response comes with a specific status code. You can specify +:success+ to indicate 200, +:redirect+ to indicate 300-399, +:missing+ to indicate 404, or +:error+ to match the 500-599 range|
|
@@ -500,6 +500,8 @@ If you're familiar with the HTTP protocol, you'll know that +get+ is a type of r
|
|
500
500
|
|
501
501
|
All of request types are methods that you can use, however, you'll probably end up using the first two more often than the others.
|
502
502
|
|
503
|
+
NOTE: Functional tests do not verify whether the specified request type should be accepted by the action. Request types in this context exist to make your tests more descriptive.
|
504
|
+
|
503
505
|
h4. The Four Hashes of the Apocalypse
|
504
506
|
|
505
507
|
After a request has been made by using one of the 5 methods (+get+, +post+, etc.) and processed, you will have 4 Hash objects ready for use:
|
@@ -512,12 +514,12 @@ After a request has been made by using one of the 5 methods (+get+, +post+, etc.
|
|
512
514
|
As is the case with normal Hash objects, you can access the values by referencing the keys by string. You can also reference them by symbol name, except for +assigns+. For example:
|
513
515
|
|
514
516
|
<ruby>
|
515
|
-
|
516
|
-
|
517
|
-
|
517
|
+
flash["gordon"] flash[:gordon]
|
518
|
+
session["shmession"] session[:shmession]
|
519
|
+
cookies["are_good_for_u"] cookies[:are_good_for_u]
|
518
520
|
|
519
521
|
# Because you can't use assigns[:something] for historical reasons:
|
520
|
-
|
522
|
+
assigns["something"] assigns(:something)
|
521
523
|
</ruby>
|
522
524
|
|
523
525
|
h4. Instance Variables Available
|
@@ -582,7 +584,7 @@ assert_select "ol" do
|
|
582
584
|
end
|
583
585
|
</ruby>
|
584
586
|
|
585
|
-
The +assert_select+ assertion is quite powerful. For more advanced usage, refer to its "documentation":http://api.rubyonrails.org/classes/
|
587
|
+
The +assert_select+ assertion is quite powerful. For more advanced usage, refer to its "documentation":http://api.rubyonrails.org/classes/ActionDispatch/Assertions/SelectorAssertions.html.
|
586
588
|
|
587
589
|
h5. Additional View-Based Assertions
|
588
590
|
|
@@ -590,7 +592,6 @@ There are more assertions that are primarily used in testing views:
|
|
590
592
|
|
591
593
|
|_.Assertion |_.Purpose|
|
592
594
|
|+assert_select_email+ |Allows you to make assertions on the body of an e-mail. |
|
593
|
-
|+assert_select_rjs+ |Allows you to make assertions on an RJS response. +assert_select_rjs+ has variants which allow you to narrow down on the updated element or even a particular operation on an element.|
|
594
595
|
|+assert_select_encoded+ |Allows you to make assertions on encoded HTML. It does this by un-encoding the contents of each element and then calling the block with all the un-encoded elements.|
|
595
596
|
|+css_select(selector)+ or +css_select(element, selector)+ |Returns an array of all the elements selected by the _selector_. In the second variant it first matches the base _element_ and tries to match the _selector_ expression on any of its children. If there are no matches both variants return an empty array.|
|
596
597
|
|
@@ -619,7 +620,7 @@ Here's what a freshly-generated integration test looks like:
|
|
619
620
|
<ruby>
|
620
621
|
require 'test_helper'
|
621
622
|
|
622
|
-
class UserFlowsTest <
|
623
|
+
class UserFlowsTest < ActionDispatch::IntegrationTest
|
623
624
|
fixtures :all
|
624
625
|
|
625
626
|
# Replace this with your real tests.
|
@@ -629,7 +630,7 @@ class UserFlowsTest < ActionController::IntegrationTest
|
|
629
630
|
end
|
630
631
|
</ruby>
|
631
632
|
|
632
|
-
Integration tests inherit from +
|
633
|
+
Integration tests inherit from +ActionDispatch::IntegrationTest+. This makes available some additional helpers to use in your integration tests. Also you need to explicitly include the fixtures to be made available to the test.
|
633
634
|
|
634
635
|
h4. Helpers Available for Integration Tests
|
635
636
|
|
@@ -655,7 +656,7 @@ A simple integration test that exercises multiple controllers:
|
|
655
656
|
<ruby>
|
656
657
|
require 'test_helper'
|
657
658
|
|
658
|
-
class UserFlowsTest <
|
659
|
+
class UserFlowsTest < ActionDispatch::IntegrationTest
|
659
660
|
fixtures :users
|
660
661
|
|
661
662
|
test "login and browse site" do
|
@@ -683,7 +684,7 @@ Here's an example of multiple sessions and custom DSL in an integration test
|
|
683
684
|
<ruby>
|
684
685
|
require 'test_helper'
|
685
686
|
|
686
|
-
class UserFlowsTest <
|
687
|
+
class UserFlowsTest < ActionDispatch::IntegrationTest
|
687
688
|
fixtures :users
|
688
689
|
|
689
690
|
test "login and browse site" do
|
@@ -740,13 +741,14 @@ You don't need to set up and run your tests by hand on a test-by-test basis. Rai
|
|
740
741
|
|+rake test:plugins+ |Run all the plugin tests from +vendor/plugins/*/**/test+ (or specify with +PLUGIN=_name_+)|
|
741
742
|
|+rake test:profile+ |Profile the performance tests|
|
742
743
|
|+rake test:recent+ |Tests recent changes|
|
743
|
-
|+rake test:uncommitted+ |Runs all the tests which are uncommitted.
|
744
|
+
|+rake test:uncommitted+ |Runs all the tests which are uncommitted. Supports Subversion and Git|
|
744
745
|
|+rake test:units+ |Runs all the unit tests from +test/unit+|
|
745
746
|
|
746
747
|
|
747
748
|
h3. Brief Note About +Test::Unit+
|
748
749
|
|
749
|
-
Ruby ships with a boat load of libraries. One little gem of a library is +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
|
750
|
+
Ruby ships with a boat load of libraries. One little gem of a library is +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
|
751
|
+
us to use all of the basic assertions in our tests.
|
750
752
|
|
751
753
|
NOTE: For more information on +Test::Unit+, refer to "test/unit Documentation":http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/
|
752
754
|
|
@@ -939,8 +941,8 @@ h3. Other Testing Approaches
|
|
939
941
|
The built-in +test/unit+ based testing is not the only way to test Rails applications. Rails developers have come up with a wide variety of other approaches and aids for testing, including:
|
940
942
|
|
941
943
|
* "NullDB":http://avdi.org/projects/nulldb/, a way to speed up testing by avoiding database use.
|
942
|
-
* "Factory Girl":
|
943
|
-
* "Machinist":
|
944
|
+
* "Factory Girl":https://github.com/thoughtbot/factory_girl/tree/master, a replacement for fixtures.
|
945
|
+
* "Machinist":https://github.com/notahat/machinist/tree/master, another replacement for fixtures.
|
944
946
|
* "Shoulda":http://www.thoughtbot.com/projects/shoulda, an extension to +test/unit+ with additional helpers, macros, and assertions.
|
945
947
|
* "RSpec":http://rspec.info/, a behavior-driven development framework
|
946
948
|
|
data/guides/w3c_validator.rb
CHANGED
@@ -21,7 +21,7 @@
|
|
21
21
|
#
|
22
22
|
# Separate many using commas:
|
23
23
|
#
|
24
|
-
# # validates only
|
24
|
+
# # validates only association_basics.html and migrations.html
|
25
25
|
# ONLY=assoc,migrations rake validate_guides
|
26
26
|
#
|
27
27
|
# ---------------------------------------------------------------------------
|
@@ -88,4 +88,4 @@ module RailsGuides
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
-
RailsGuides::Validator.new.validate
|
91
|
+
RailsGuides::Validator.new.validate
|