aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVijay Dev <vijaydev.cse@gmail.com>2012-05-30 22:53:52 +0530
committerVijay Dev <vijaydev.cse@gmail.com>2012-05-30 22:53:52 +0530
commitec74763c393c6a5f54eb64f0313610aead7f815a (patch)
tree39e3712c4cfc589083ed5072b6b8373361334441
parent0406a13fac7f809cb511e45583259e66d8739b4f (diff)
parent032f502f1221129d8446d3e25cd8956469b43456 (diff)
downloadrails-ec74763c393c6a5f54eb64f0313610aead7f815a.tar.gz
rails-ec74763c393c6a5f54eb64f0313610aead7f815a.tar.bz2
rails-ec74763c393c6a5f54eb64f0313610aead7f815a.zip
Merge branch 'master' of github.com:lifo/docrails
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb2
-rw-r--r--activerecord/README.rdoc8
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb2
-rw-r--r--activerecord/lib/active_record/relation/batches.rb27
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb25
-rw-r--r--activesupport/lib/active_support/core_ext/array/access.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb65
-rw-r--r--activesupport/lib/active_support/core_ext/class/subclasses.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb20
-rw-r--r--activesupport/lib/active_support/json/decoding.rb5
-rw-r--r--activesupport/lib/active_support/json/encoding.rb5
-rw-r--r--guides/source/action_view_overview.textile22
-rw-r--r--guides/source/active_support_instrumentation.textile4
-rw-r--r--guides/source/command_line.textile198
-rw-r--r--guides/source/contributing_to_ruby_on_rails.textile36
-rw-r--r--guides/source/engines.textile6
-rw-r--r--guides/source/migrations.textile3
-rw-r--r--guides/source/security.textile68
19 files changed, 328 insertions, 208 deletions
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index ae923de24e..82892593f8 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -35,7 +35,7 @@ module ActionView
end
end
- # Renders the given template. An string representing the layout can be
+ # Renders the given template. A string representing the layout can be
# supplied as well.
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
view, locals = @view, locals || {}
diff --git a/activerecord/README.rdoc b/activerecord/README.rdoc
index 30a66ff5f0..d080e0b0f5 100644
--- a/activerecord/README.rdoc
+++ b/activerecord/README.rdoc
@@ -61,10 +61,10 @@ A short rundown of some of the major features:
* Validation rules that can differ for new or existing objects.
class Account < ActiveRecord::Base
- validates_presence_of :subdomain, :name, :email_address, :password
- validates_uniqueness_of :subdomain
- validates_acceptance_of :terms_of_service, :on => :create
- validates_confirmation_of :password, :email_address, :on => :create
+ validates :subdomain, :name, :email_address, :password, presence: true
+ validates :subdomain, uniqueness: true
+ validates :terms_of_service, acceptance: true, on: :create
+ validates :password, :email_address, confirmation: true, on: :create
end
{Learn more}[link:classes/ActiveRecord/Validations.html]
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 2176fc4e40..2fb80fdc4c 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -522,7 +522,7 @@ module ActiveRecord
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
# # ]
#
- # person.pets.delete([Pet.find(1), Pet.find(3)])
+ # person.pets.delete(Pet.find(1), Pet.find(3))
# # => [
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index 15f838a5ab..fb4388d4b2 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -2,20 +2,26 @@ require 'active_support/core_ext/object/blank'
module ActiveRecord
module Batches
- # Yields each record that was found by the find +options+. The find is
- # performed by find_in_batches with a batch size of 1000 (or as
+ # Looping through a collection of records from the database
+ # (using the +all+ method, for example) is very inefficient
+ # since it will try to instantiate all the objects at once.
+ #
+ # In that case, batch processing methods allow you to work
+ # with the records in batches, thereby greatly reducing memory consumption.
+ #
+ # The <tt>find_each</tt> method uses <tt>find_in_batches</tt> with a batch size of 1000 (or as
# specified by the <tt>:batch_size</tt> option).
#
- # Example:
+ # Person.all.find_each do |person|
+ # person.do_awesome_stuff
+ # end
#
# Person.where("age > 21").find_each do |person|
# person.party_all_night!
# end
#
- # Note: This method is only intended to use for batch processing of
- # large amounts of records that wouldn't fit in memory all at once. If
- # you just need to loop over less than 1000 records, it's probably
- # better just to use the regular find methods.
+ # You can also pass the <tt>:start</tt> option to specify
+ # an offset to control the starting point.
def find_each(options = {})
find_in_batches(options) do |records|
records.each { |record| yield record }
@@ -39,12 +45,15 @@ module ActiveRecord
# primary keys. You can't set the limit either, that's used to control
# the batch sizes.
#
- # Example:
- #
# Person.where("age > 21").find_in_batches do |group|
# sleep(50) # Make sure it doesn't get too crowded in there!
# group.each { |person| person.party_all_night! }
# end
+ #
+ # # Let's process the next 2000 records
+ # Person.all.find_in_batches(start: 2000, batch_size: 2000) do |group|
+ # group.each { |person| person.party_all_night! }
+ # end
def find_in_batches(options = {})
options.assert_valid_keys(:start, :batch_size)
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 04b4fcf379..ad49c80e4f 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -129,7 +129,7 @@ module ActiveRecord
# Person.all.map(&:name)
#
# Pluck returns an <tt>Array</tt> of attribute values type-casted to match
- # the plucked column name, if it can be deduced. Plucking a SQL fragment
+ # the plucked column name, if it can be deduced. Plucking an SQL fragment
# returns String values by default.
#
# Examples:
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 4fedd33d64..5f6898b45a 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -7,8 +7,6 @@ module ActiveRecord
# If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
# is an integer, find by id coerces its arguments using +to_i+.
#
- # ==== Examples
- #
# Person.find(1) # returns the object for ID = 1
# Person.find("1") # returns the object for ID = 1
# Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
@@ -49,7 +47,6 @@ module ActiveRecord
#
# Post.find_by name: 'Spartacus', rating: 4
# Post.find_by "published_at < ?", 2.weeks.ago
- #
def find_by(*args)
where(*args).take
end
@@ -64,8 +61,6 @@ module ActiveRecord
# order. The order will depend on the database implementation.
# If an order is supplied it will be respected.
#
- # Examples:
- #
# Person.take # returns an object fetched by SELECT * FROM people
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
# Person.where(["name LIKE '%?'", name]).take
@@ -82,12 +77,11 @@ module ActiveRecord
# Find the first record (or first N records if a parameter is supplied).
# If no order is defined it will order by primary key.
#
- # Examples:
- #
# Person.first # returns the first object fetched by SELECT * FROM people
# Person.where(["user_name = ?", user_name]).first
# Person.where(["user_name = :u", { :u => user_name }]).first
# Person.order("created_on DESC").offset(5).first
+ # Person.first(3) # returns the first three objects fetched by SELECT * FROM people LIMIT 3
def first(limit = nil)
if limit
if order_values.empty? && primary_key
@@ -109,11 +103,18 @@ module ActiveRecord
# Find the last record (or last N records if a parameter is supplied).
# If no order is defined it will order by primary key.
#
- # Examples:
- #
# Person.last # returns the last object fetched by SELECT * FROM people
# Person.where(["user_name = ?", user_name]).last
# Person.order("created_on DESC").offset(5).last
+ # Person.last(3) # returns the last three objects fetched by SELECT * FROM people.
+ #
+ # Take note that in that last case, the results are sorted in ascending order:
+ #
+ # [#<Person id:2>, #<Person id:3>, #<Person id:4>]
+ #
+ # and not:
+ #
+ # [#<Person id:4>, #<Person id:3>, #<Person id:2>]
def last(limit = nil)
if limit
if order_values.empty? && primary_key
@@ -132,7 +133,8 @@ module ActiveRecord
last or raise RecordNotFound
end
- # Examples:
+ # Runs the query on the database and returns records with the used query
+ # methods.
#
# Person.all # returns an array of objects for all the rows fetched by SELECT * FROM people
# Person.where(["category IN (?)", categories]).limit(50).all
@@ -163,11 +165,10 @@ module ActiveRecord
# 'Jamie'</tt>), since it would be sanitized and then queried against
# the primary key column, like <tt>id = 'name = \'Jamie\''</tt>.
#
- # ==== Examples
# Person.exists?(5)
# Person.exists?('5')
- # Person.exists?(:name => "David")
# Person.exists?(['name LIKE ?', "%#{query}%"])
+ # Person.exists?(:name => "David")
# Person.exists?
def exists?(id = false)
id = id.id if ActiveRecord::Model === id
diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb
index 44d90ef732..a8f9dddae5 100644
--- a/activesupport/lib/active_support/core_ext/array/access.rb
+++ b/activesupport/lib/active_support/core_ext/array/access.rb
@@ -1,40 +1,48 @@
class Array
# Returns the tail of the array from +position+.
#
- # %w( a b c d ).from(0) # => %w( a b c d )
- # %w( a b c d ).from(2) # => %w( c d )
- # %w( a b c d ).from(10) # => %w()
- # %w().from(0) # => %w()
+ # %w( a b c d ).from(0) # => ["a", "b", "c", "d"]
+ # %w( a b c d ).from(2) # => ["c", "d"]
+ # %w( a b c d ).from(10) # => []
+ # %w().from(0) # => []
def from(position)
self[position, length] || []
end
# Returns the beginning of the array up to +position+.
#
- # %w( a b c d ).to(0) # => %w( a )
- # %w( a b c d ).to(2) # => %w( a b c )
- # %w( a b c d ).to(10) # => %w( a b c d )
- # %w().to(0) # => %w()
+ # %w( a b c d ).to(0) # => ["a"]
+ # %w( a b c d ).to(2) # => ["a", "b", "c"]
+ # %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
+ # %w().to(0) # => []
def to(position)
first position + 1
end
# Equal to <tt>self[1]</tt>.
+ #
+ # %w( a b c d e).second # => "b"
def second
self[1]
end
# Equal to <tt>self[2]</tt>.
+ #
+ # %w( a b c d e).third # => "c"
def third
self[2]
end
# Equal to <tt>self[3]</tt>.
+ #
+ # %w( a b c d e).fourth # => "d"
def fourth
self[3]
end
# Equal to <tt>self[4]</tt>.
+ #
+ # %w( a b c d e).fifth # => "e"
def fifth
self[4]
end
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 24aa28b895..1e0de651c7 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -4,10 +4,55 @@ require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/string/inflections'
class Array
- # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
- # * <tt>:words_connector</tt> - The sign or word used to join the elements in arrays with two or more elements (default: ", ")
- # * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ")
- # * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ")
+ # Converts the array to a comma-separated sentence where the last element is
+ # joined by the connector word.
+ #
+ # You can pass the following options to change the default behaviour. If you
+ # pass an option key that doesn't exist in the list below, it will raise an
+ # <tt>ArgumentError</tt>.
+ #
+ # Options:
+ #
+ # * <tt>:words_connector</tt> - The sign or word used to join the elements
+ # in arrays with two or more elements (default: ", ").
+ # * <tt>:two_words_connector</tt> - The sign or word used to join the elements
+ # in arrays with two elements (default: " and ").
+ # * <tt>:last_word_connector</tt> - The sign or word used to join the last element
+ # in arrays with three or more elements (default: ", and ").
+ # * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
+ # the connector options defined on the 'support.array' namespace in the
+ # corresponding dictionary file.
+ #
+ # [].to_sentence # => ""
+ # ['one'].to_sentence # => "one"
+ # ['one', 'two'].to_sentence # => "one and two"
+ # ['one', 'two', 'three'].to_sentence # => "one, two, and three"
+ #
+ # ['one', 'two'].to_sentence(passing: 'invalid option')
+ # # => ArgumentError: Unknown key :passing
+ #
+ # ['one', 'two'].to_sentence(two_words_connector: '-')
+ # # => "one-two"
+ #
+ # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
+ # # => "one or two or at least three"
+ #
+ # Examples using <tt>:locale</tt> option:
+ #
+ # # Given this locale dictionary:
+ # # 
+ # # es:
+ # # support:
+ # # array:
+ # # words_connector: " o "
+ # # two_words_connector: " y "
+ # # last_word_connector: " o al menos "
+ #
+ # ['uno', 'dos'].to_sentence(locale: :es)
+ # # => "uno y dos"
+ #
+ # ['uno', 'dos', 'tres'].to_sentence(locale: :es)
+ # # => "uno o dos o al menos tres"
def to_sentence(options = {})
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
@@ -39,7 +84,17 @@ class Array
end
# Converts a collection of elements into a formatted string by calling
- # <tt>to_s</tt> on all elements and joining them:
+ # <tt>to_s</tt> on all elements and joining them. Having this model:
+ #
+ # class Blog < ActiveRecord::Base
+ # def to_s
+ # title
+ # end
+ # end
+ #
+ # Blog.all.map(&:title) #=> ["First Post", "Second Post", "Third post"]
+ #
+ # <tt>to_formatted_s</tt> shows us:
#
# Blog.all.to_formatted_s # => "First PostSecond PostThird Post"
#
diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb
index 74ea047c24..c2e0ebb3d4 100644
--- a/activesupport/lib/active_support/core_ext/class/subclasses.rb
+++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb
@@ -1,11 +1,11 @@
require 'active_support/core_ext/module/anonymous'
require 'active_support/core_ext/module/reachable'
-class Class #:nodoc:
+class Class
begin
ObjectSpace.each_object(Class.new) {}
- def descendants
+ def descendants # :nodoc:
descendants = []
ObjectSpace.each_object(singleton_class) do |k|
descendants.unshift k unless k == self
@@ -13,7 +13,7 @@ class Class #:nodoc:
descendants
end
rescue StandardError # JRuby
- def descendants
+ def descendants # :nodoc:
descendants = []
ObjectSpace.each_object(Class) do |k|
descendants.unshift k if k < self
@@ -25,7 +25,13 @@ class Class #:nodoc:
# Returns an array with the direct children of +self+.
#
- # Integer.subclasses # => [Bignum, Fixnum]
+ # Integer.subclasses # => [Fixnum, Bignum]
+ #
+ # class Foo; end
+ # class Bar < Foo; end
+ # class Baz < Foo; end
+ #
+ # Foo.subclasses # => [Baz, Bar]
def subclasses
subclasses, chain = [], descendants
chain.each do |k|
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index b8cb2e347f..672cc0256f 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -46,19 +46,19 @@ class Module
# Extends the module object with module and instance accessors for class attributes,
# just like the native attr* accessors for instance attributes.
#
- # module AppConfiguration
- # mattr_accessor :google_api_key
+ # module AppConfiguration
+ # mattr_accessor :google_api_key
#
- # self.google_api_key = "123456789"
- # end
+ # self.google_api_key = "123456789"
+ # end
#
- # AppConfiguration.google_api_key # => "123456789"
- # AppConfiguration.google_api_key = "overriding the api key!"
- # AppConfiguration.google_api_key # => "overriding the api key!"
+ # AppConfiguration.google_api_key # => "123456789"
+ # AppConfiguration.google_api_key = "overriding the api key!"
+ # AppConfiguration.google_api_key # => "overriding the api key!"
#
- # To opt out of the instance writer method, pass instance_writer: false.
- # To opt out of the instance reader method, pass instance_reader: false.
- # To opt out of both instance methods, pass instance_accessor: false.
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
+ # To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
def mattr_accessor(*syms)
mattr_reader(*syms)
mattr_writer(*syms)
diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb
index 986a764479..72fd97ceee 100644
--- a/activesupport/lib/active_support/json/decoding.rb
+++ b/activesupport/lib/active_support/json/decoding.rb
@@ -8,6 +8,11 @@ module ActiveSupport
module JSON
class << self
+ # Parses a JSON string (JavaScript Object Notation) into a hash.
+ # See www.json.org for more info.
+ #
+ # ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
+ # => {"team" => "rails", "players" => "36"}
def decode(json, options ={})
data = MultiJson.load(json, options)
if ActiveSupport.parse_json_times
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 41fe61e790..ded02c873a 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -25,7 +25,10 @@ module ActiveSupport
# matches YAML-formatted dates
DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
- # Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.
+ # Dumps objects in JSON (JavaScript Object Notation). See www.json.org for more info.
+ #
+ # ActiveSupport::JSON.encode({team: 'rails', players: '36'})
+ # # => "{\"team\":\"rails\",\"players\":\"36\"}"
def self.encode(value, options = nil)
Encoding::Encoder.new(options).encode(value)
end
diff --git a/guides/source/action_view_overview.textile b/guides/source/action_view_overview.textile
index 734fdd895b..fdfa97effa 100644
--- a/guides/source/action_view_overview.textile
+++ b/guides/source/action_view_overview.textile
@@ -454,7 +454,7 @@ input("post", "title") # =>
h4. RecordTagHelper
-This module provides methods for generating a container tag, such as a +<div>+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use.
+This module provides methods for generating container tags, such as +div+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use.
h5. content_tag_for
@@ -580,13 +580,13 @@ h5. image_path
Computes the path to an image asset in the +app/assets/images+ directory. Full paths from the document root will be passed through. Used internally by +image_tag+ to build the image path.
<ruby>
-image_path("edit.png") # => /images/edit.png
+image_path("edit.png") # => /assets/edit.png
</ruby>
Fingerprint will be added to the filename if config.assets.digest is set to true.
<ruby>
-image_path("edit.png") # => /images/edit-2d1a2db63fc738690021fedb5a65b68e.png
+image_path("edit.png") # => /assets/edit-2d1a2db63fc738690021fedb5a65b68e.png
</ruby>
h5. image_url
@@ -594,7 +594,7 @@ h5. image_url
Computes the url to an image asset in the +app/asset/images+ directory. This will call +image_path+ internally and merge with your current host or your asset host.
<ruby>
-image_url("edit.png") # => http://www.example.com/images/edit.png
+image_url("edit.png") # => http://www.example.com/assets/edit.png
</ruby>
h5. image_tag
@@ -602,7 +602,7 @@ h5. image_tag
Returns an html image tag for the source. The source can be a full path or a file that exists in your +app/assets/images+ directory.
<ruby>
-image_tag("icon.png") # => <img src="/images/icon.png" alt="Icon" />
+image_tag("icon.png") # => <img src="/assets/icon.png" alt="Icon" />
</ruby>
h5. javascript_include_tag
@@ -610,8 +610,7 @@ h5. javascript_include_tag
Returns an html script tag for each of the sources provided. You can pass in the filename (+.js+ extension is optional) of JavaScript files that exist in your +app/assets/javascripts+ directory for inclusion into the current page or you can pass the full path relative to your document root.
<ruby>
-javascript_include_tag "common" # =>
- <script src="/javascripts/common.js"></script>
+javascript_include_tag "common" # => <script src="/assets/common.js"></script>
</ruby>
If the application does not use the asset pipeline, to include the jQuery JavaScript library in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +app/assets/javascripts+ directory, it will be included as well.
@@ -638,7 +637,7 @@ h5. javascript_path
Computes the path to a JavaScript asset in the +app/assets/javascripts+ directory. If the source filename has no extension, +.js+ will be appended. Full paths from the document root will be passed through. Used internally by +javascript_include_tag+ to build the script path.
<ruby>
-javascript_path "common" # => /javascripts/common.js
+javascript_path "common" # => /assets/common.js
</ruby>
h5. javascript_url
@@ -646,7 +645,7 @@ h5. javascript_url
Computes the url to a JavaScript asset in the +app/assets/javascripts+ directory. This will call +javascript_path+ internally and merge with your current host or your asset host.
<ruby>
-javascript_url "common" # => http://www.example.com/javascripts/common.js
+javascript_url "common" # => http://www.example.com/assets/common.js
</ruby>
h5. stylesheet_link_tag
@@ -654,8 +653,7 @@ h5. stylesheet_link_tag
Returns a stylesheet link tag for the sources specified as arguments. If you don't specify an extension, +.css+ will be appended automatically.
<ruby>
-stylesheet_link_tag "application" # =>
- <link href="/assets/application.css" media="screen" rel="stylesheet" />
+stylesheet_link_tag "application" # => <link href="/assets/application.css" media="screen" rel="stylesheet" />
</ruby>
You can also include all styles in the stylesheet directory using :all as the source:
@@ -668,7 +666,7 @@ You can also cache multiple stylesheets into one file, which requires less HTTP
<ruby>
stylesheet_link_tag :all, :cache => true
- <link href="/assets/all.css" media="screen" rel="stylesheet" />
+# => <link href="/assets/all.css" media="screen" rel="stylesheet" />
</ruby>
h5. stylesheet_path
diff --git a/guides/source/active_support_instrumentation.textile b/guides/source/active_support_instrumentation.textile
index 430549fba4..dcdd9d14f5 100644
--- a/guides/source/active_support_instrumentation.textile
+++ b/guides/source/active_support_instrumentation.textile
@@ -15,7 +15,7 @@ h3. Introduction to instrumentation
The instrumentation API provided by ActiveSupport allows developers to provide hooks which other developers may hook into. There are several of these within the Rails framework, as described below in <TODO: link to section detailing each hook point>. With this API, developers can choose to be notified when certain events occur inside their application or another piece of Ruby code.
-For example, there is a hook provided within Active Record that is called every time Active Record uses a SQL query on a database. This hook could be *subscribed* to, and used to track the number of queries during a certain action. There's another hook around the processing of an action of a controller. This could be used, for instance, to track how long a specific action has taken.
+For example, there is a hook provided within Active Record that is called every time Active Record uses an SQL query on a database. This hook could be *subscribed* to, and used to track the number of queries during a certain action. There's another hook around the processing of an action of a controller. This could be used, for instance, to track how long a specific action has taken.
You are even able to create your own events inside your application which you can later subscribe to.
@@ -377,7 +377,7 @@ listen to any notification.
The block receives the following arguments:
# The name of the event
-# Time when is started
+# Time when it started
# Time when it finished
# An unique ID for this event
# The payload (described in previous sections)
diff --git a/guides/source/command_line.textile b/guides/source/command_line.textile
index b656a0857a..19e42cea93 100644
--- a/guides/source/command_line.textile
+++ b/guides/source/command_line.textile
@@ -31,20 +31,21 @@ h4. +rails new+
The first thing we'll want to do is create a new Rails application by running the +rails new+ command after installing Rails.
-TIP: You can install the rails gem by typing +gem install rails+, if you don't have it already.
+INFO: You can install the rails gem by typing +gem install rails+, if you don't have it already.
<shell>
$ rails new commandsapp
create
create README.rdoc
- create .gitignore
create Rakefile
create config.ru
+ create .gitignore
create Gemfile
create app
...
create tmp/cache
- create tmp/pids
+ ...
+ run bundle install
</shell>
Rails will set you up with what seems like a huge amount of stuff for such a tiny command! You've got the entire Rails directory structure now with all the code you need to run our simple application right out of the box.
@@ -61,17 +62,17 @@ With no further work, +rails server+ will run our new shiny Rails app:
$ cd commandsapp
$ rails server
=> Booting WEBrick
-=> Rails 3.1.0 application starting in development on http://0.0.0.0:3000
+=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
-[2010-04-18 03:20:33] INFO WEBrick 1.3.1
-[2010-04-18 03:20:33] INFO ruby 1.8.7 (2010-01-10) [x86_64-linux]
-[2010-04-18 03:20:33] INFO WEBrick::HTTPServer#start: pid=26086 port=3000
+[2012-05-28 00:39:41] INFO WEBrick 1.3.1
+[2012-05-28 00:39:41] INFO ruby 1.9.2 (2011-02-18) [x86_64-darwin11.2.0]
+[2012-05-28 00:39:41] INFO WEBrick::HTTPServer#start: pid=69680 port=3000
</shell>
With just three commands we whipped up a Rails server listening on port 3000. Go to your browser and open "http://localhost:3000":http://localhost:3000, you will see a basic Rails app running.
-You can also use the alias "s" to start the server: <tt>rails s</tt>.
+INFO: You can also use the alias "s" to start the server: <tt>rails s</tt>.
The server can be run on a different port using the +-p+ option. The default development environment can be changed using +-e+.
@@ -85,7 +86,7 @@ h4. +rails generate+
The +rails generate+ command uses templates to create a whole lot of things. Running +rails generate+ by itself gives a list of available generators:
-You can also use the alias "g" to invoke the generator command: <tt>rails g</tt>.
+INFO: You can also use the alias "g" to invoke the generator command: <tt>rails g</tt>.
<shell>
$ rails generate
@@ -97,6 +98,7 @@ Usage: rails generate GENERATOR [args] [options]
Please choose a generator below.
Rails:
+ assets
controller
generator
...
@@ -118,23 +120,22 @@ Usage: rails generate controller NAME [action action] [options]
...
...
+Description:
+ ...
+
+ To create a controller within a module, specify the controller name as a
+ path like 'parent_module/controller_name'.
+
+ ...
+
Example:
- rails generate controller CreditCard open debit credit close
+ `rails generate controller CreditCard open debit credit close`
Credit card controller with URLs like /credit_card/debit.
- Controller: app/controllers/credit_card_controller.rb
- Views: app/views/credit_card/debit.html.erb [...]
- Helper: app/helpers/credit_card_helper.rb
- Test: test/functional/credit_card_controller_test.rb
-
-Modules Example:
- rails generate controller 'admin/credit_card' suspend late_fee
-
- Credit card admin controller with URLs like /admin/credit_card/suspend.
- Controller: app/controllers/admin/credit_card_controller.rb
- Views: app/views/admin/credit_card/debit.html.erb [...]
- Helper: app/helpers/admin/credit_card_helper.rb
- Test: test/functional/admin/credit_card_controller_test.rb
+ Controller: app/controllers/credit_card_controller.rb
+ Functional Test: test/functional/credit_card_controller_test.rb
+ Views: app/views/credit_card/debit.html.erb [...]
+ Helper: app/helpers/credit_card_helper.rb
</shell>
The controller generator is expecting parameters in the form of +generate controller ControllerName action1 action2+. Let's make a +Greetings+ controller with an action of *hello*, which will say something nice to us.
@@ -153,10 +154,10 @@ $ rails generate controller Greetings hello
invoke test_unit
create test/unit/helpers/greetings_helper_test.rb
invoke assets
- create app/assets/javascripts/greetings.js
- invoke css
- create app/assets/stylesheets/greetings.css
-
+ invoke coffee
+ create app/assets/javascripts/greetings.js.coffee
+ invoke scss
+ create app/assets/stylesheets/greetings.css.scss
</shell>
What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a view file, a functional test file, a helper for the view, a javascript file and a stylesheet file.
@@ -193,21 +194,19 @@ Rails comes with a generator for data models too.
<shell>
$ rails generate model
-Usage: rails generate model NAME [field:type field:type] [options]
+Usage:
+ rails generate model NAME [field[:type][:index] field[:type][:index]] [options]
...
-Examples:
- rails generate model account
-
- Model: app/models/account.rb
- Test: test/unit/account_test.rb
- Fixtures: test/fixtures/accounts.yml
- Migration: db/migrate/XXX_add_accounts.rb
+ActiveRecord options:
+ [--migration] # Indicates when to generate migration
+ # Default: true
- rails generate model post title:string body:text published:boolean
+...
- Creates a Post model with a string title, text body, and published flag.
+Description:
+ Create rails files for model generator.
</shell>
NOTE: For a list of available field types, refer to the "API documentation":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column for the column method for the +TableDefinition+ class.
@@ -218,46 +217,47 @@ We will set up a simple resource called "HighScore" that will keep track of our
<shell>
$ rails generate scaffold HighScore game:string score:integer
- exists app/models/
- exists app/controllers/
- exists app/helpers/
- create app/views/high_scores
- create app/views/layouts/
- exists test/functional/
- create test/unit/
- create app/assets/stylesheets/
- create app/views/high_scores/index.html.erb
- create app/views/high_scores/show.html.erb
- create app/views/high_scores/new.html.erb
- create app/views/high_scores/edit.html.erb
- create app/views/layouts/high_scores.html.erb
- create app/assets/stylesheets/scaffold.css.scss
- create app/controllers/high_scores_controller.rb
- create test/functional/high_scores_controller_test.rb
- create app/helpers/high_scores_helper.rb
- route resources :high_scores
-dependency model
- exists app/models/
- exists test/unit/
- create test/fixtures/
+ invoke active_record
+ create db/migrate/20120528060026_create_high_scores.rb
create app/models/high_score.rb
- create test/unit/high_score_test.rb
- create test/fixtures/high_scores.yml
- exists db/migrate
- create db/migrate/20100209025147_create_high_scores.rb
+ invoke test_unit
+ create test/unit/high_score_test.rb
+ create test/fixtures/high_scores.yml
+ route resources :high_scores
+ invoke scaffold_controller
+ create app/controllers/high_scores_controller.rb
+ invoke erb
+ create app/views/high_scores
+ create app/views/high_scores/index.html.erb
+ create app/views/high_scores/edit.html.erb
+ create app/views/high_scores/show.html.erb
+ create app/views/high_scores/new.html.erb
+ create app/views/high_scores/_form.html.erb
+ invoke test_unit
+ create test/functional/high_scores_controller_test.rb
+ invoke helper
+ create app/helpers/high_scores_helper.rb
+ invoke test_unit
+ create test/unit/helpers/high_scores_helper_test.rb
+ invoke assets
+ invoke coffee
+ create app/assets/javascripts/high_scores.js.coffee
+ invoke scss
+ create app/assets/stylesheets/high_scores.css.scss
+ invoke scss
+ create app/assets/stylesheets/scaffolds.css.scss
</shell>
The generator checks that there exist the directories for models, controllers, helpers, layouts, functional and unit tests, stylesheets, creates the views, controller, model and database migration for HighScore (creating the +high_scores+ table and fields), takes care of the route for the *resource*, and new tests for everything.
-The migration requires that we *migrate*, that is, run some Ruby code (living in that +20100209025147_create_high_scores.rb+) to modify the schema of our database. Which database? The sqlite3 database that Rails will create for you when we run the +rake db:migrate+ command. We'll talk more about Rake in-depth in a little while.
+The migration requires that we *migrate*, that is, run some Ruby code (living in that +20120528060026_create_high_scores.rb+) to modify the schema of our database. Which database? The sqlite3 database that Rails will create for you when we run the +rake db:migrate+ command. We'll talk more about Rake in-depth in a little while.
<shell>
$ rake db:migrate
-(in /home/foobar/commandsapp)
== CreateHighScores: migrating ===============================================
-- create_table(:high_scores)
- -> 0.0026s
-== CreateHighScores: migrated (0.0028s) ======================================
+ -> 0.0017s
+== CreateHighScores: migrated (0.0019s) ======================================
</shell>
INFO: Let's talk about unit tests. Unit tests are code that tests and makes assertions about code. In unit testing, we take a little part of code, say a method of a model, and test its inputs and outputs. Unit tests are your friend. The sooner you make peace with the fact that your quality of life will drastically increase when you unit test your code, the better. Seriously. We'll make one in a moment.
@@ -274,19 +274,19 @@ h4. +rails console+
The +console+ command lets you interact with your Rails application from the command line. On the underside, +rails console+ uses IRB, so if you've ever used it, you'll be right at home. This is useful for testing out quick ideas with code and changing data server-side without touching the website.
-You can also use the alias "c" to invoke the console: <tt>rails c</tt>.
+INFO: You can also use the alias "c" to invoke the console: <tt>rails c</tt>.
-You can specify the environment in which the +console+ command should operate using the +-e+ switch.
+You can specify the environment in which the +console+ command should operate.
<shell>
-$ rails console -e staging
+$ rails console staging
</shell>
If you wish to test out some code without changing any data, you can do that by invoking +rails console --sandbox+.
<shell>
$ rails console --sandbox
-Loading development environment in sandbox (Rails 3.1.0)
+Loading development environment in sandbox (Rails 3.2.3)
Any modifications you make will be rolled back on exit
irb(main):001:0>
</shell>
@@ -295,7 +295,7 @@ h4. +rails dbconsole+
+rails dbconsole+ figures out which database you're using and drops you into whichever command line interface you would use with it (and figures out the command line parameters to give to it, too!). It supports MySQL, PostgreSQL, SQLite and SQLite3.
-You can also use the alias "db" to invoke the dbconsole: <tt>rails db</tt>.
+INFO: You can also use the alias "db" to invoke the dbconsole: <tt>rails db</tt>.
h4. +rails runner+
@@ -305,7 +305,7 @@ h4. +rails runner+
$ rails runner "Model.long_running_method"
</shell>
-You can also use the alias "r" to invoke the runner: <tt>rails r</tt>.
+INFO: You can also use the alias "r" to invoke the runner: <tt>rails r</tt>.
You can specify the environment in which the +runner+ command should operate using the +-e+ switch.
@@ -317,31 +317,25 @@ h4. +rails destroy+
Think of +destroy+ as the opposite of +generate+. It'll figure out what generate did, and undo it.
-You can also use the alias "d" to invoke the destroy command: <tt>rails d</tt>.
+INFO: You can also use the alias "d" to invoke the destroy command: <tt>rails d</tt>.
<shell>
$ rails generate model Oops
- exists app/models/
- exists test/unit/
- exists test/fixtures/
- create app/models/oops.rb
- create test/unit/oops_test.rb
- create test/fixtures/oops.yml
- exists db/migrate
- create db/migrate/20081221040817_create_oops.rb
+ invoke active_record
+ create db/migrate/20120528062523_create_oops.rb
+ create app/models/oops.rb
+ invoke test_unit
+ create test/unit/oops_test.rb
+ create test/fixtures/oops.yml
+</shell>
+<shell>
$ rails destroy model Oops
- notempty db/migrate
- notempty db
- rm db/migrate/20081221040817_create_oops.rb
- rm test/fixtures/oops.yml
- rm test/unit/oops_test.rb
- rm app/models/oops.rb
- notempty test/fixtures
- notempty test
- notempty test/unit
- notempty test
- notempty app/models
- notempty app
+ invoke active_record
+ remove db/migrate/20120528062523_create_oops.rb
+ remove app/models/oops.rb
+ invoke test_unit
+ remove test/unit/oops_test.rb
+ remove test/fixtures/oops.yml
</shell>
h3. Rake
@@ -352,16 +346,16 @@ You can get a list of Rake tasks available to you, which will often depend on yo
<shell>
$ rake --tasks
-(in /home/foobar/commandsapp)
-rake db:abort_if_pending_migrations # Raises an error if there are pending migrations
-rake db:charset # Retrieves the charset for the current environment's database
-rake db:collation # Retrieves the collation for the current environment's database
-rake db:create # Create the database defined in config/database.yml for the current Rails.env
+rake about # List versions of all Rails frameworks and the environment
+rake assets:clean # Remove compiled assets
+rake assets:precompile # Compile all the assets named in config.assets.precompile
+rake db:create # Create the database from config/database.yml for the current Rails.env
...
+rake log:clear # Truncates all *.log files in log/ to zero bytes
+rake middleware # Prints out your Rack middleware stack
...
-rake tmp:pids:clear # Clears all files in tmp/pids
-rake tmp:sessions:clear # Clears all files in tmp/sessions
-rake tmp:sockets:clear # Clears all files in tmp/sockets
+rake tmp:clear # Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp:sockets:clear)
+rake tmp:create # Creates tmp directories for sessions, cache, sockets, and pids
</shell>
h4. +about+
diff --git a/guides/source/contributing_to_ruby_on_rails.textile b/guides/source/contributing_to_ruby_on_rails.textile
index 72cdea885f..acf75d41cd 100644
--- a/guides/source/contributing_to_ruby_on_rails.textile
+++ b/guides/source/contributing_to_ruby_on_rails.textile
@@ -412,6 +412,42 @@ Push to your remote:
$ git push mine my_new_branch
</shell>
+You might have cloned your forked repository into your machine and might want to add the original Rails repository as a remote instead, if that's the case here's what you have to do.
+
+In the directory you cloned your fork:
+
+<shell>
+$ git remote add rails git://github.com/rails/rails.git
+</shell>
+
+Download new commits and branches from the official repository:
+
+<shell>
+$ git fetch rails
+</shell>
+
+Merge the new content:
+
+<shell>
+$ git checkout master
+$ git rebase rails/master
+</shell>
+
+Update your fork:
+
+<shell>
+$ git push origin master
+</shell>
+
+If you want to update another branches:
+
+<shell>
+$ git checkout branch_name
+$ git rebase rails/branch_name
+$ git push origin branch_name
+</shell>
+
+
h4. Issue a Pull Request
Navigate to the Rails repository you just pushed to (e.g. https://github.com/your-user-name/rails) and press "Pull Request" in the upper right hand corner.
diff --git a/guides/source/engines.textile b/guides/source/engines.textile
index c35305a822..86e7254201 100644
--- a/guides/source/engines.textile
+++ b/guides/source/engines.textile
@@ -36,6 +36,12 @@ To generate an engine with Rails 3.1, you will need to run the plugin generator
$ rails plugin new blorgh --full --mountable
</shell>
+The full list of options for the plugin generator may be seen by typing:
+
+<shell>
+$ rails plugin --help
+</shell>
+
The +--full+ option tells the plugin generator that you want to create an engine (which is a mountable plugin, hence the option name), creating the basic directory structure of an engine by providing things such as the foundations of an +app+ folder, as well a +config/routes.rb+ file. This generator also provides a file at +lib/blorgh/engine.rb+ which is identical in function to an application's +config/application.rb+ file.
The +--mountable+ option tells the generator to mount the engine inside the dummy testing application located at +test/dummy+ inside the engine. It does this by placing this line in to the dummy application's +config/routes.rb+ file, located at +test/dummy/config/routes.rb+ inside the engine:
diff --git a/guides/source/migrations.textile b/guides/source/migrations.textile
index 52dba76e68..342b5a4d57 100644
--- a/guides/source/migrations.textile
+++ b/guides/source/migrations.textile
@@ -8,8 +8,7 @@ production machines next time you deploy.
Active Record tracks which migrations have already been run so all you have to
do is update your source and run +rake db:migrate+. Active Record will work out
-which migrations should be run. It will also update your +db/schema.rb+ file to
-match the structure of your database.
+which migrations should be run. Active Record will also update your +db/schema.rb+ file to match the up-to-date structure of your database.
Migrations also allow you to describe these transformations using Ruby. The
great thing about this is that (like most of Active Record's functionality) it
diff --git a/guides/source/security.textile b/guides/source/security.textile
index cc0894fc77..0931dd6393 100644
--- a/guides/source/security.textile
+++ b/guides/source/security.textile
@@ -30,7 +30,7 @@ A good place to start looking at security is with sessions, which can be vulnera
h4. What are Sessions?
--- _HTTP is a stateless protocol. Sessions make it stateful._
+NOTE: _HTTP is a stateless protocol. Sessions make it stateful._
Most applications need to keep track of certain state of a particular user. This could be the contents of a shopping basket or the user id of the currently logged in user. Without the idea of sessions, the user would have to identify, and probably authenticate, on every request.
Rails will create a new session automatically if a new user accesses the application. It will load an existing session if the user has already used the application.
@@ -44,13 +44,13 @@ User.find(session[:user_id])
h4. Session id
--- _The session id is a 32 byte long MD5 hash value._
+NOTE: _The session id is a 32 byte long MD5 hash value._
A session id consists of the hash value of a random string. The random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. Currently it is not feasible to brute-force Rails' session ids. To date MD5 is uncompromised, but there have been collisions, so it is theoretically possible to create another input text with the same hash value. But this has had no security impact to date.
h4. Session Hijacking
--- _Stealing a user's session id lets an attacker use the web application in the victim's name._
+WARNING: _Stealing a user's session id lets an attacker use the web application in the victim's name._
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.
@@ -72,7 +72,7 @@ The main objective of most attackers is to make money. The underground prices fo
h4. Session Guidelines
--- _Here are some general guidelines on sessions._
+Here are some general guidelines on sessions.
* _(highlight)Do not store large objects in a session_. Instead you should store them in the database and save their id in the session. This will eliminate synchronization headaches and it won't fill up your session storage space (depending on what session storage you chose, see below).
This will also be a good idea, if you modify the structure of an object and old versions of it are still in some user's cookies. With server-side session storages you can clear out the sessions, but with client-side storages, this is hard to mitigate.
@@ -81,7 +81,7 @@ This will also be a good idea, if you modify the structure of an object and old
h4. Session Storage
--- _Rails provides several storage mechanisms for the session hashes. The most important are ActiveRecord::SessionStore and ActionDispatch::Session::CookieStore._
+NOTE: _Rails provides several storage mechanisms for the session hashes. The most important are +ActiveRecord::SessionStore+ and +ActionDispatch::Session::CookieStore+._
There are a number of session storages, i.e. where Rails saves the session hash and session id. Most real-live applications choose ActiveRecord::SessionStore (or one of its derivatives) over file storage due to performance and maintenance reasons. ActiveRecord::SessionStore keeps the session id and hash in a database table and saves and retrieves the hash on every request.
@@ -104,7 +104,7 @@ There are, however, derivatives of CookieStore which encrypt the session hash, s
h4. Replay Attacks for CookieStore Sessions
--- _Another sort of attack you have to be aware of when using CookieStore is the replay attack._
+TIP: _Another sort of attack you have to be aware of when using +CookieStore+ is the replay attack._
It works like this:
@@ -120,7 +120,7 @@ The best _(highlight)solution against it is not to store this kind of data in a
h4. Session Fixation
--- _Apart from stealing a user's session id, the attacker may fix a session id known to him. This is called session fixation._
+NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to him. This is called session fixation._
!images/session_fixation.png(Session fixation)!
@@ -135,7 +135,7 @@ This attack focuses on fixing a user's session id known to the attacker, and for
h4. Session Fixation – Countermeasures
--- _One line of code will protect you from session fixation._
+TIP: _One line of code will protect you from session fixation._
The most effective countermeasure is to _(highlight)issue a new session identifier_ and declare the old one invalid after a successful login. That way, an attacker cannot use the fixed session identifier. This is a good countermeasure against session hijacking, as well. Here is how to create a new session in Rails:
@@ -149,7 +149,7 @@ Another countermeasure is to _(highlight)save user-specific properties in the se
h4. Session Expiry
--- _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._
+NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._
One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _(highlight)expire sessions in a database table_. Call +Session.sweep("20 minutes")+ to expire sessions that were used longer than 20 minutes ago.
@@ -174,7 +174,7 @@ delete_all "updated_at < '#{time.ago.to_s(:db)}' OR
h3. Cross-Site Request Forgery (CSRF)
--- _This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands._
+This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands.
!images/csrf.png!
@@ -193,7 +193,7 @@ CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) -- less t
h4. CSRF Countermeasures
--- _First, as is required by the W3C, use GET and POST appropriately. Secondly, a security token in non-GET requests will protect your application from CSRF._
+NOTE: _First, as is required by the W3C, use GET and POST appropriately. Secondly, a security token in non-GET requests will protect your application from CSRF._
The HTTP protocol basically provides two main types of requests - GET and POST (and more, but they are not supported by most browsers). The World Wide Web Consortium (W3C) provides a checklist for choosing HTTP GET or POST:
@@ -255,7 +255,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f
h4. Redirection
--- _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, he may also create a self-contained attack._
+WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, he may also create a self-contained attack._
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:
@@ -283,7 +283,7 @@ This example is a Base64 encoded JavaScript which displays a simple message box.
h4. File Uploads
--- _Make sure file uploads don't overwrite important files, and process media files asynchronously._
+NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._
Many web applications allow users to upload files. _(highlight)File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so – one more reason to run web servers, database servers and other programs as a less privileged Unix user.
@@ -308,7 +308,7 @@ The solution to this is best to _(highlight)process media files asynchronously_:
h4. Executable Code in File Uploads
--- _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._
+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._
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.
@@ -316,7 +316,7 @@ _(highlight)If your Apache DocumentRoot points to Rails' /public directory, do n
h4. File Downloads
--- _Make sure users cannot download arbitrary files._
+NOTE: _Make sure users cannot download arbitrary files._
Just as you have to filter file names for uploads, you have to do so for downloads. The send_file() method sends files from the server to the client. If you use a file name, that the user entered, without filtering, any file can be downloaded:
@@ -338,7 +338,7 @@ Another (additional) approach is to store the file names in the database and nam
h3. Intranet and Admin Security
--- _Intranet and administration interfaces are popular attack targets, because they allow privileged access. Although this would require several extra-security measures, the opposite is the case in the real world._
+Intranet and administration interfaces are popular attack targets, because they allow privileged access. Although this would require several extra-security measures, the opposite is the case in the real world.
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.

@@ -370,7 +370,7 @@ The common admin interface works like this: it's located at www.example.com/admi
h3. Mass Assignment
--- _Without any precautions Model.new(params[:model]) allows attackers to set any database column's value._
+WARNING: _Without any precautions +Model.new(params[:model]+) allows attackers to set any database column's value._
The mass-assignment feature may become a problem, as it allows an attacker to set any model's attributes by manipulating the hash passed to a model's +new()+ method:
@@ -482,7 +482,7 @@ This will create an empty whitelist of attributes available for mass-assignment
h3. User Management
--- _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._
+NOTE: _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._
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.
@@ -509,7 +509,7 @@ And thus it found the first user in the database, returned it and logged him in.
h4. Brute-Forcing Accounts
--- _Brute-force attacks on accounts are trial and error attacks on the login credentials. Fend them off with more generic error messages and possibly require to enter a CAPTCHA._
+NOTE: _Brute-force attacks on accounts are trial and error attacks on the login credentials. Fend them off with more generic error messages and possibly require to enter a CAPTCHA._
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.
@@ -521,7 +521,7 @@ In order to mitigate such attacks, _(highlight)display a generic error message o
h4. Account Hijacking
--- _Many web applications make it easy to hijack user accounts. Why not be different and make it more difficult?_
+Many web applications make it easy to hijack user accounts. Why not be different and make it more difficult?.
h5. Passwords
@@ -537,7 +537,7 @@ Depending on your web application, there may be more ways to hijack the user's a
h4. CAPTCHAs
--- _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._
+INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._
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":http://ambethia.com/recaptcha/ is also a Rails plug-in with the same name as the API.
@@ -564,7 +564,7 @@ Note that this protects you only from automatic bots, targeted tailor-made bots
h4. Logging
--- _Tell Rails not to put passwords in the log files._
+WARNING: _Tell Rails not to put passwords in the log files._
By default, Rails logs all requests being made to the web application. But log files can be a huge security issue, as they may contain login credentials, credit card numbers et cetera. When designing a web application security concept, you should also think about what will happen if an attacker got (full) access to the web server. Encrypting secrets and passwords in the database will be quite useless, if the log files list them in clear text. You can _(highlight)filter certain request parameters from your log files_ by appending them to <tt>config.filter_parameters</tt> in the application configuration. These parameters will be marked [FILTERED] in the log.
@@ -574,7 +574,7 @@ config.filter_parameters << :password
h4. Good Passwords
--- _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._
+INFO: _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._
Bruce Schneier, a security technologist, "has analyzed":http://www.schneier.com/blog/archives/2006/12/realworld_passw.html 34,000 real-world user names and passwords from the MySpace phishing attack mentioned <a href="#examples-from-the-underground">below</a>. It turns out that most of the passwords are quite easy to crack. The 20 most common passwords are:
@@ -586,7 +586,7 @@ A good password is a long alphanumeric combination of mixed cases. As this is qu
h4. Regular Expressions
--- _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._
+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._
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 make this wrong. So how is this a security threat? Imagine you have a File model and you validate the file name by a regular expression like this:
@@ -610,7 +610,7 @@ Whereas %0A is a line feed in URL encoding, so Rails automatically converts it t
h4. Privilege Escalation
--- _Changing a single parameter may give the user unauthorized access. Remember that every parameter may be changed, no matter how much you hide or obfuscate it._
+WARNING: _Changing a single parameter may give the user unauthorized access. Remember that every parameter may be changed, no matter how much you hide or obfuscate it._
The most common parameter that a user might tamper with, is the id parameter, as in +http://www.domain.com/project/1+, whereas 1 is the id. It will be available in params in the controller. There, you will most likely do something like this:
@@ -630,13 +630,13 @@ Don't be fooled by security by obfuscation and JavaScript security. The Web Deve
h3. Injection
--- _Injection is a class of attacks that introduce malicious code or parameters into a web application in order to run it within its security context. Prominent examples of injection are cross-site scripting (XSS) and SQL injection._
+INFO: _Injection is a class of attacks that introduce malicious code or parameters into a web application in order to run it within its security context. Prominent examples of injection are cross-site scripting (XSS) and SQL injection._
Injection is very tricky, because the same code or parameter can be malicious in one context, but totally harmless in another. A context can be a scripting, query or programming language, the shell or a Ruby/Rails method. The following sections will cover all important contexts where injection attacks may happen. The first section, however, covers an architectural decision in connection with Injection.
h4. Whitelists versus Blacklists
--- _When sanitizing, protecting or verifying something, whitelists over blacklists._
+NOTE: _When sanitizing, protecting or verifying something, whitelists over blacklists._
A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _(highlight)prefer to use whitelist approaches_:
@@ -651,7 +651,7 @@ Whitelists are also a good approach against the human factor of forgetting somet
h4. SQL Injection
--- _Thanks to clever methods, this is hardly a problem in most Rails applications. However, this is a very devastating and common attack in web applications, so it is important to understand the problem._
+INFO: _Thanks to clever methods, this is hardly a problem in most Rails applications. However, this is a very devastating and common attack in web applications, so it is important to understand the problem._
h5(#sql-injection-introduction). Introduction
@@ -730,7 +730,7 @@ The array or hash form is only available in model instances. You can try +saniti
h4. Cross-Site Scripting (XSS)
--- _The most widespread, and one of the most devastating security vulnerabilities in web applications is XSS. This malicious attack injects client-side executable code. Rails provides helper methods to fend these attacks off._
+INFO: _The most widespread, and one of the most devastating security vulnerabilities in web applications is XSS. This malicious attack injects client-side executable code. Rails provides helper methods to fend these attacks off._
h5. Entry Points
@@ -858,7 +858,7 @@ The MySpace Samy worm will be discussed in the CSS Injection section.
h4. CSS Injection
--- _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._
+INFO: _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._
CSS Injection is explained best by a well-known worm, the "MySpace Samy worm":http://namb.la/popular/tech.html. This worm automatically sent a friend request to Samy (the attacker) simply by visiting his profile. Within several hours he had over 1 million friend requests, but it creates too much traffic on MySpace, so that the site goes offline. The following is a technical explanation of the worm.
@@ -898,7 +898,7 @@ This example, again, showed that a blacklist filter is never complete. However,
h4. Textile Injection
--- _If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. "RedCloth":http://redcloth.org/ is such a language for Ruby, but without precautions, it is also vulnerable to XSS._
+If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. "RedCloth":http://redcloth.org/ is such a language for Ruby, but without precautions, it is also vulnerable to XSS.
For example, RedCloth translates +_test_+ to &lt;em&gt;test&lt;em&gt;, which makes the text italic. However, up to the current version 3.0.4, it is still vulnerable to XSS. Get the "all-new version 4":http://www.redcloth.org that removed serious bugs. However, even that version has "some security bugs":http://www.rorsecurity.info/journal/2008/10/13/new-redcloth-security.html, so the countermeasures still apply. Here is an example for version 3.0.4:
@@ -927,13 +927,13 @@ It is recommended to _(highlight)use RedCloth in combination with a whitelist in
h4. Ajax Injection
--- _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._
+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._
If you use the "in_place_editor plugin":http://dev.rubyonrails.org/browser/plugins/in_place_editing, or actions that return a string, rather than rendering a view, _(highlight)you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
h4. Command Line Injection
--- _Use user-supplied command line parameters with caution._
+NOTE: _Use user-supplied command line parameters with caution._
If your application has to execute commands in the underlying operating system, there are several methods in Ruby: exec(command), syscall(command), system(command) and `command`. You will have to be especially careful with these functions if the user may enter the whole command, or a part of it. This is because in most shells, you can execute another command at the end of the first one, concatenating them with a semicolon (;) or a vertical bar (|).
@@ -947,7 +947,7 @@ system("/bin/echo","hello; rm *")
h4. Header Injection
--- _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._
+WARNING: _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._
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. _(highlight)Remember to escape these header fields, too._ For example when you display the user agent in an administration area.