aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile3
-rw-r--r--actionpack/lib/abstract_controller/url_for.rb2
-rw-r--r--actionview/CHANGELOG.md6
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb12
-rw-r--r--actionview/test/template/asset_tag_helper_test.rb15
-rw-r--r--activerecord/CHANGELOG.md10
-rw-r--r--activerecord/Rakefile2
-rw-r--r--activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb4
-rw-r--r--activerecord/lib/active_record/relation.rb16
-rw-r--r--activerecord/lib/active_record/transactions.rb13
-rw-r--r--activerecord/test/cases/relations_test.rb6
-rw-r--r--activerecord/test/cases/transactions_test.rb13
-rw-r--r--activerecord/test/config.example.yml30
-rw-r--r--activesupport/CHANGELOG.md5
-rw-r--r--activesupport/lib/active_support/subscriber.rb11
-rw-r--r--activesupport/test/subscriber_test.rb25
-rw-r--r--guides/code/getting_started/Gemfile6
-rw-r--r--guides/source/active_support_core_extensions.md6
-rw-r--r--guides/source/api_documentation_guidelines.md4
-rw-r--r--guides/source/asset_pipeline.md8
-rw-r--r--guides/source/caching_with_rails.md2
-rw-r--r--guides/source/migrations.md5
-rw-r--r--guides/source/security.md14
-rw-r--r--guides/source/testing.md2
-rw-r--r--guides/source/upgrading_ruby_on_rails.md14
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb14
-rw-r--r--railties/lib/rails/tasks/framework.rake2
27 files changed, 176 insertions, 74 deletions
diff --git a/Gemfile b/Gemfile
index 4108c7e179..43efc925d9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -39,6 +39,9 @@ local_gemfile = File.dirname(__FILE__) + "/.Gemfile"
instance_eval File.read local_gemfile if File.exist? local_gemfile
group :test do
+ # FIX: Our test suite isn't ready to run in random order yet
+ gem 'minitest', '< 5.3.4'
+
platforms :mri_19 do
gem 'ruby-prof', '~> 0.11.2'
end
diff --git a/actionpack/lib/abstract_controller/url_for.rb b/actionpack/lib/abstract_controller/url_for.rb
index 4a95e1f276..72d07b0927 100644
--- a/actionpack/lib/abstract_controller/url_for.rb
+++ b/actionpack/lib/abstract_controller/url_for.rb
@@ -11,7 +11,7 @@ module AbstractController
def _routes
raise "In order to use #url_for, you must include routing helpers explicitly. " \
- "For instance, `include Rails.application.routes.url_helpers"
+ "For instance, `include Rails.application.routes.url_helpers`."
end
module ClassMethods
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index e5740e30c6..147e5b47db 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Allow custom `:host` option to be passed to `asset_url` helper that
+ overwrites `config.action_controller.asset_host` for particular asset.
+
+ *Hubert Łępicki*
+
* Deprecate `AbstractController::Base.parent_prefixes`.
Override `AbstractController::Base.local_prefixes` when you want to change
where to find views.
@@ -95,5 +100,4 @@
*Piotr Chmolowski, Łukasz Strzałkowski*
-
Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/actionview/CHANGELOG.md) for previous changes.
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index 41997a85b3..ae684af87b 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -147,7 +147,14 @@ module ActionView
# Computes the full URL to an asset in the public directory. This
# will use +asset_path+ internally, so most of their behaviors
- # will be the same.
+ # will be the same. If :host options is set, it overwrites global
+ # +config.action_controller.asset_host+ setting.
+ #
+ # All other options provided are forwarded to +asset_path+ call.
+ #
+ # asset_url "application.js" # => http://example.com/application.js
+ # asset_url "application.js", host: "http://cdn.example.com" # => http://cdn.example.com/javascripts/application.js
+ #
def asset_url(source, options = {})
path_to_asset(source, options.merge(:protocol => :request))
end
@@ -191,7 +198,8 @@ module ActionView
# (proc or otherwise).
def compute_asset_host(source = "", options = {})
request = self.request if respond_to?(:request)
- host = config.asset_host if defined? config.asset_host
+ host = options[:host]
+ host ||= config.asset_host if defined? config.asset_host
host ||= request.base_url if request && options[:protocol] == :request
if host.respond_to?(:call)
diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb
index 18e4277d7a..343681b5a9 100644
--- a/actionview/test/template/asset_tag_helper_test.rb
+++ b/actionview/test/template/asset_tag_helper_test.rb
@@ -596,6 +596,10 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_equal "gopher://www.example.com", compute_asset_host("foo", :protocol => :request)
end
+ def test_should_return_custom_host_if_passed_in_options
+ assert_equal "http://custom.example.com", compute_asset_host("foo", :host => "http://custom.example.com")
+ end
+
def test_should_ignore_relative_root_path_on_complete_url
assert_dom_equal(%(http://www.example.com/images/xml.png), image_path("http://www.example.com/images/xml.png"))
end
@@ -759,4 +763,15 @@ class AssetUrlHelperEmptyModuleTest < ActionView::TestCase
assert @module.config.asset_host
assert_equal "http://www.example.com/foo", @module.asset_url("foo")
end
+
+ def test_asset_url_with_custom_asset_host
+ @module.instance_eval do
+ def config
+ Struct.new(:asset_host).new("http://www.example.com")
+ end
+ end
+
+ assert @module.config.asset_host
+ assert_equal "http://custom.example.com/foo", @module.asset_url("foo", :host => "http://custom.example.com")
+ end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 5647204859..2b305dfa37 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Restrict deletion of record when using `delete_all` with `uniq`, `group`, `having`
+ or `offset`.
+
+ In these cases the generated query ignored them and that caused unintended
+ records to be deleted.
+
+ Fixes #11985.
+
+ *Leandro Facchinetti*
+
* Floats with limit >= 25 that get turned into doubles in MySQL no longer have
their limit dropped from the schema.
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 84856774f2..01ca4c82f2 100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -45,7 +45,7 @@ namespace :db do
task drop: ['mysql:drop_databases', 'postgresql:drop_databases']
end
-%w( mysql mysql2 postgresql sqlite3 sqlite3_mem firebird db2 oracle sybase openbase frontbase jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb ).each do |adapter|
+%w( mysql mysql2 postgresql sqlite3 sqlite3_mem db2 oracle jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb ).each do |adapter|
Rake::TestTask.new("test_#{adapter}") { |t|
adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z0-9]+/]
t.libs << 'test'
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
index a297439214..44486ad758 100644
--- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
@@ -25,8 +25,8 @@ module ActiveRecord::Associations::Builder
class_name = options.fetch(:class_name) {
model_name = name.to_s.camelize.singularize
- if parent_name = lhs_class.parent_name
- model_name = model_name.prepend("#{parent_name}::")
+ if lhs_class.parent_name
+ model_name.prepend("#{lhs_class.parent_name}::")
end
model_name
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 24b33ab0a8..d92ff781ee 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -12,6 +12,7 @@ module ActiveRecord
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
:reverse_order, :distinct, :create_with, :uniq]
+ INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
@@ -430,12 +431,21 @@ module ActiveRecord
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
# +after_destroy+ callbacks, use the +destroy_all+ method instead.
#
- # If a limit scope is supplied, +delete_all+ raises an ActiveRecord error:
+ # If an invalid method is supplied, +delete_all+ raises an ActiveRecord error:
#
# Post.limit(100).delete_all
- # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit scope
+ # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
def delete_all(conditions = nil)
- raise ActiveRecordError.new("delete_all doesn't support limit scope") if self.limit_value
+ invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
+ if MULTI_VALUE_METHODS.include?(method)
+ send("#{method}_values").any?
+ else
+ send("#{method}_value")
+ end
+ }
+ if invalid_methods.any?
+ raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
+ end
if conditions
where(conditions).delete_all
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 17f76b63b3..17d1ae1ba0 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -1,5 +1,3 @@
-require 'thread'
-
module ActiveRecord
# See ActiveRecord::Transactions::ClassMethods for documentation.
module Transactions
@@ -295,7 +293,7 @@ module ActiveRecord
def committed! #:nodoc:
run_callbacks :commit if destroyed? || persisted?
ensure
- @_start_transaction_state.clear
+ force_clear_transaction_record_state
end
# Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record
@@ -328,7 +326,7 @@ module ActiveRecord
begin
status = yield
rescue ActiveRecord::Rollback
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ clear_transaction_record_state
status = nil
end
@@ -355,7 +353,12 @@ module ActiveRecord
# Clear the new record state and id of a record.
def clear_transaction_record_state #:nodoc:
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
- @_start_transaction_state.clear if @_start_transaction_state[:level] < 1
+ force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
+ end
+
+ # Force to clear the transaction record state.
+ def force_clear_transaction_record_state #:nodoc:
+ @_start_transaction_state.clear
end
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 6a880c6680..6ab1bd8c8b 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -831,8 +831,12 @@ class RelationTest < ActiveRecord::TestCase
assert davids.loaded?
end
- def test_delete_all_limit_error
+ def test_delete_all_with_unpermitted_relation_raises_error
assert_raises(ActiveRecord::ActiveRecordError) { Author.limit(10).delete_all }
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.uniq.delete_all }
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.group(:name).delete_all }
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.having('SUM(id) < 3').delete_all }
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.offset(10).delete_all }
end
def test_select_with_aggregates
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index e6ed85394b..de1f624191 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -123,6 +123,19 @@ class TransactionTest < ActiveRecord::TestCase
assert !Topic.find(1).approved?
end
+ def test_rolling_back_in_a_callback_rollbacks_before_save
+ def @first.before_save_for_transaction
+ raise ActiveRecord::Rollback
+ end
+ assert !@first.approved
+
+ Topic.transaction do
+ @first.approved = true
+ @first.save!
+ end
+ assert !Topic.find(@first.id).approved?, "Should not commit the approved flag"
+ end
+
def test_raising_exception_in_nested_transaction_restore_state_in_save
topic = Topic.new
diff --git a/activerecord/test/config.example.yml b/activerecord/test/config.example.yml
index 479b8c050d..a54914c372 100644
--- a/activerecord/test/config.example.yml
+++ b/activerecord/test/config.example.yml
@@ -51,28 +51,6 @@ connections:
password: arunit
database: arunit2
- firebird:
- arunit:
- host: localhost
- username: rails
- password: rails
- charset: UTF8
- arunit2:
- host: localhost
- username: rails
- password: rails
- charset: UTF8
-
- frontbase:
- arunit:
- host: localhost
- username: rails
- session_name: unittest-<%= $$ %>
- arunit2:
- host: localhost
- username: rails
- session_name: unittest-<%= $$ %>
-
mysql:
arunit:
username: rails
@@ -130,11 +108,3 @@ connections:
arunit2:
adapter: sqlite3
database: ':memory:'
-
- sybase:
- arunit:
- host: database_ASE
- username: sa
- arunit2:
- host: database_ASE
- username: sa
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 866a5a958d..79133c7a40 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Fixed `ActiveSupport::Subscriber` so that no duplicate subscriber is created
+ when a subscriber method is redefined.
+
+ *Dennis Schön*
+
* Remove deprecated string based terminators for `ActiveSupport::Callbacks`.
*Eileen M. Uchitelle*
diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb
index 4b9b48539f..98be78b41b 100644
--- a/activesupport/lib/active_support/subscriber.rb
+++ b/activesupport/lib/active_support/subscriber.rb
@@ -64,12 +64,21 @@ module ActiveSupport
def add_event_subscriber(event)
return if %w{ start finish }.include?(event.to_s)
- notifier.subscribe("#{event}.#{namespace}", subscriber)
+ pattern = "#{event}.#{namespace}"
+
+ # don't add multiple subscribers (eg. if methods are redefined)
+ return if subscriber.patterns.include?(pattern)
+
+ subscriber.patterns << pattern
+ notifier.subscribe(pattern, subscriber)
end
end
+ attr_reader :patterns # :nodoc:
+
def initialize
@queue_key = [self.class.name, object_id].join "-"
+ @patterns = []
super
end
diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb
index 253411aa3d..8be8c51f07 100644
--- a/activesupport/test/subscriber_test.rb
+++ b/activesupport/test/subscriber_test.rb
@@ -4,20 +4,27 @@ require 'active_support/subscriber'
class TestSubscriber < ActiveSupport::Subscriber
attach_to :doodle
- cattr_reader :event
+ cattr_reader :events
def self.clear
- @@event = nil
+ @@events = []
end
def open_party(event)
- @@event = event
+ events << event
end
private
def private_party(event)
- @@event = event
+ events << event
+ end
+end
+
+# Monkey patch subscriber to test that only one subscriber per method is added.
+class TestSubscriber
+ def open_party(event)
+ events << event
end
end
@@ -29,12 +36,18 @@ class SubscriberTest < ActiveSupport::TestCase
def test_attaches_subscribers
ActiveSupport::Notifications.instrument("open_party.doodle")
- assert_equal "open_party.doodle", TestSubscriber.event.name
+ assert_equal "open_party.doodle", TestSubscriber.events.first.name
+ end
+
+ def test_attaches_only_one_subscriber
+ ActiveSupport::Notifications.instrument("open_party.doodle")
+
+ assert_equal 1, TestSubscriber.events.size
end
def test_does_not_attach_private_methods
ActiveSupport::Notifications.instrument("private_party.doodle")
- assert_nil TestSubscriber.event
+ assert_equal TestSubscriber.events, []
end
end
diff --git a/guides/code/getting_started/Gemfile b/guides/code/getting_started/Gemfile
index c3d7e96c4d..091a87aa4c 100644
--- a/guides/code/getting_started/Gemfile
+++ b/guides/code/getting_started/Gemfile
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.0'
-# Use sqlite3 as the database for Active Record
+# Use SQLite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.1'
@@ -14,7 +14,7 @@ gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
-# Use jquery as the JavaScript library
+# Use jQuery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
@@ -29,7 +29,7 @@ gem 'spring', group: :development
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
-# Use unicorn as the app server
+# Use Unicorn as the app server
# gem 'unicorn'
# Use Capistrano for deployment
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index 8d0d6d260d..dfe9d30698 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -572,12 +572,12 @@ NOTE: Defined in `active_support/core_ext/module/aliasing.rb`.
#### `alias_attribute`
-Model attributes have a reader, a writer, and a predicate. You can alias a model attribute having the corresponding three methods defined for you in one shot. As in other aliasing methods, the new name is the first argument, and the old name is the second (my mnemonic is they go in the same order as if you did an assignment):
+Model attributes have a reader, a writer, and a predicate. You can alias a model attribute having the corresponding three methods defined for you in one shot. As in other aliasing methods, the new name is the first argument, and the old name is the second (one mnemonic is that they go in the same order as if you did an assignment):
```ruby
class User < ActiveRecord::Base
- # let me refer to the email column as "login",
- # possibly meaningful for authentication code
+ # You can refer to the email column as "login".
+ # This can be meaningful for authentication code.
alias_attribute :login, :email
end
```
diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md
index 261538d0be..6c3c7468b1 100644
--- a/guides/source/api_documentation_guidelines.md
+++ b/guides/source/api_documentation_guidelines.md
@@ -175,8 +175,8 @@ end
The API is careful not to commit to any particular value, the method has
predicate semantics, that's enough.
-Filenames
----------
+File Names
+----------
As a rule of thumb, use filenames relative to the application root:
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index 52fc9726d9..950cfdca29 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -913,6 +913,14 @@ that it plays nicely with the pipeline. You may find quirks related to your
specific set up, you may not. The defaults nginx uses, for example, should give
you no problems when used as an HTTP cache.
+If you want to serve only some assets from your CDN, you can use custom
+`:host` option of `asset_url` helper, which overwrites value set in
+`config.action_controller.asset_host`.
+
+```ruby
+asset_url 'image.png', :host => 'http://cdn.example.com'
+```
+
Customizing the Pipeline
------------------------
diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md
index b6423dd44e..c652aa6a80 100644
--- a/guides/source/caching_with_rails.md
+++ b/guides/source/caching_with_rails.md
@@ -105,7 +105,7 @@ This method generates a cache key that depends on all products and can be used i
<% end %>
```
-If you want to cache a fragment under certain condition you can use `cache_if` or `cache_unless`
+If you want to cache a fragment under certain condition you can use `cache_if` or `cache_unless`
```erb
<% cache_if (condition, cache_key_for_products) do %>
diff --git a/guides/source/migrations.md b/guides/source/migrations.md
index c61ccfe94a..fe1a6a4697 100644
--- a/guides/source/migrations.md
+++ b/guides/source/migrations.md
@@ -902,6 +902,11 @@ schema into a RDBMS other than the one used to create it.
Because schema dumps are the authoritative source for your database schema, it
is strongly recommended that you check them into source control.
+`db/schema.rb` contains the current version number of the database. This
+ensures conflicts are going to happen in the case of a merge where both
+branches touched the schema. When that happens, solve conflicts manually,
+keeping the highest version number of the two.
+
Active Record and Referential Integrity
---------------------------------------
diff --git a/guides/source/security.md b/guides/source/security.md
index 0f4d4e712b..75d8c8e4c8 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -17,7 +17,7 @@ After reading this guide, you will know:
Introduction
------------
-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.
+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.
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).
@@ -25,7 +25,7 @@ The Gartner Group however estimates that 75% of attacks are at the web applicati
The threats against web applications include user account hijacking, bypass of access control, reading or modifying sensitive data, or presenting fraudulent content. Or an attacker might be able to install a Trojan horse program or unsolicited e-mail sending software, aim at financial enrichment or cause brand name damage by modifying company resources. In order to prevent attacks, minimize their impact and remove points of attack, first of all, you have to fully understand the attack methods in order to find the correct countermeasures. That is what this guide aims at.
-In order to develop secure web applications you have to keep up to date on all layers and know your enemies. To keep up to date subscribe to security mailing lists, read security blogs and make updating and security checks a habit (check the <a href="#additional-resources">Additional Resources</a> chapter). I do it manually because that's how you find the nasty logical security problems.
+In order to develop secure web applications you have to keep up to date on all layers and know your enemies. To keep up to date subscribe to security mailing lists, read security blogs and make updating and security checks a habit (check the <a href="#additional-resources">Additional Resources</a> chapter). It is done manually because that's how you find the nasty logical security problems.
Sessions
--------
@@ -198,7 +198,7 @@ In the <a href="#sessions">session chapter</a> you have learned that most Rails
It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere - in a forum, blog post or email.
-CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) - less than 0.1% in 2006 - but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work - _CSRF is an important security issue_.
+CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) - less than 0.1% in 2006 - but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in many security contract works - _CSRF is an important security issue_.
### CSRF Countermeasures
@@ -374,7 +374,7 @@ For _countermeasures against CSRF in administration interfaces and Intranet appl
The common admin interface works like this: it's located at www.example.com/admin, may be accessed only if the admin flag is set in the User model, re-displays user input and allows the admin to delete/add/edit whatever data desired. Here are some thoughts about this:
-* It is very important to _think about the worst case_: What if someone really got hold of my cookie or user credentials. You could _introduce roles_ for the admin interface to limit the possibilities of the attacker. Or how about _special login credentials_ for the admin interface, other than the ones used for the public part of the application. Or a _special password for very serious actions_?
+* It is very important to _think about the worst case_: What if someone really got hold of your cookies or user credentials. You could _introduce roles_ for the admin interface to limit the possibilities of the attacker. Or how about _special login credentials_ for the admin interface, other than the ones used for the public part of the application. Or a _special password for very serious actions_?
* Does the admin really have to access the interface from everywhere in the world? Think about _limiting the login to a bunch of source IP addresses_. Examine request.remote_ip to find out about the user's IP address. This is not bullet-proof, but a great barrier. Remember that there might be a proxy in use, though.
@@ -406,7 +406,7 @@ If the parameter was nil, the resulting SQL query will be
SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1
```
-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.
+And thus it found the first user in the database, returned it and logged them in. You can find out more about it in [this 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.
### Brute-Forcing Accounts
@@ -732,7 +732,7 @@ Imagine a blacklist deletes "script" from the user input. Now the attacker injec
strip_tags("some<<b>script>alert('hello')<</b>/script>")
```
-This returned "some&lt;script&gt;alert('hello')&lt;/script&gt;", which makes an attack work. That's why I vote for a whitelist approach, using the updated Rails 2 method sanitize():
+This returned "some&lt;script&gt;alert('hello')&lt;/script&gt;", which makes an attack work. That's why a whitelist approach is better, using the updated Rails 2 method sanitize():
```ruby
tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p)
@@ -812,7 +812,7 @@ The [moz-binding](http://www.securiteam.com/securitynews/5LP051FHPE.html) CSS pr
#### Countermeasures
-This example, again, showed that a blacklist filter is never complete. However, as custom CSS in web applications is a quite rare feature, I am not aware of a whitelist CSS filter. _If you want to allow custom colors or images, you can allow the user to choose them and build the CSS in the web application_. Use Rails' `sanitize()` method as a model for a whitelist CSS filter, if you really need one.
+This example, again, showed that a blacklist filter is never complete. However, as custom CSS in web applications is a quite rare feature, it may be hard to find a good whitelist CSS filter. _If you want to allow custom colors or images, you can allow the user to choose them and build the CSS in the web application_. Use Rails' `sanitize()` method as a model for a whitelist CSS filter, if you really need one.
### Textile Injection
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 36d37f3af0..053d3e96a3 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -134,7 +134,7 @@ Unit Testing your Models
In Rails, models tests are what you write to test your models.
-For this guide we will be using Rails _scaffolding_. It will create the model, a migration, controller and views for the new resource in a single operation. It will also create a full test suite following Rails best practices. I will be using examples from this generated code and will be supplementing it with additional examples where necessary.
+For this guide we will be using Rails _scaffolding_. It will create the model, a migration, controller and views for the new resource in a single operation. It will also create a full test suite following Rails best practices. We will be using examples from this generated code and will be supplementing it with additional examples where necessary.
NOTE: For more information on Rails <i>scaffolding</i>, refer to [Getting Started with Rails](getting_started.html)
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index da161f84c9..30eb89ede8 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -82,10 +82,10 @@ secrets, you need to:
2. Use your existing `secret_key_base` from the `secret_token.rb` initializer to
set the SECRET_KEY_BASE environment variable for whichever users run the Rails
- app in production mode. Alternately, you can simply copy the existing
- `secret_key_base` from the `secret_token.rb` initializer to `secrets.yml`
+ app in production mode. Alternately, you can simply copy the existing
+ `secret_key_base` from the `secret_token.rb` initializer to `secrets.yml`
under the `production` section, replacing '<%= ENV["SECRET_KEY_BASE"] %>'.
-
+
3. Remove the `secret_token.rb` initializer.
4. Use `rake secret` to generate new keys for the `development` and `test` sections.
@@ -393,6 +393,14 @@ start using the more precise `:plain:`, `:html`, and `:body` options instead.
Using `render :text` may pose a security risk, as the content is sent as
`text/html`.
+### PostgreSQL json and hstore datatypes
+
+Rails 4.1 will map `json` and `hstore` columns to a string-keyed Ruby `Hash`.
+In earlier versions a `HashWithIndifferentAccess` was used. This means that
+symbol access is no longer supported. This is also the case for
+`store_accessors` based on top of `json` or `hstore` columns. Make sure to use
+string keys consistently.
+
Upgrading from Rails 3.2 to Rails 4.0
-------------------------------------
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 8675d8bc1e..073e2d7380 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -86,6 +86,16 @@ module Rails
end
end
+ def config_when_updating
+ cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb')
+
+ config
+
+ unless cookie_serializer_config_exist
+ gsub_file 'config/initializers/cookies_serializer.rb', /json/, 'marshal'
+ end
+ end
+
def database_yml
template "config/databases/#{options[:database]}.yml", "config/database.yml"
end
@@ -188,6 +198,10 @@ module Rails
build(:config)
end
+ def update_config_files
+ build(:config_when_updating)
+ end
+
def create_boot_file
template "config/boot.rb"
end
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index 3c8f8c6b87..a1c805f8aa 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -55,7 +55,7 @@ namespace :rails do
# desc "Update config/boot.rb from your current rails install"
task :configs do
invoke_from_app_generator :create_boot_file
- invoke_from_app_generator :create_config_files
+ invoke_from_app_generator :update_config_files
end
# desc "Adds new executables to the application bin/ directory"