aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activemodel/CHANGELOG.md5
-rw-r--r--activemodel/lib/active_model/errors.rb13
-rw-r--r--activemodel/lib/active_model/locale/en.yml2
-rw-r--r--activemodel/lib/active_model/validations/absence.rb4
-rw-r--r--activemodel/lib/active_model/validator.rb2
-rw-r--r--activerecord/test/models/person.rb2
-rw-r--r--activesupport/CHANGELOG.md9
-rw-r--r--activesupport/lib/active_support/callbacks.rb34
-rw-r--r--activesupport/lib/active_support/core_ext/logger.rb2
-rw-r--r--activesupport/test/callbacks_test.rb62
-rw-r--r--activesupport/test/test_test.rb10
-rw-r--r--guides/source/security.md20
12 files changed, 118 insertions, 47 deletions
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index b1d33c8692..09e6ede064 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -19,11 +19,6 @@
*Roberto Vasquez Angel*
-* Added `ActiveModel::Errors#add_on_present` method. Adds error messages to
- present attributes.
-
- *Roberto Vasquez Angel*
-
* `[attribute]_changed?` now returns `false` after a call to `reset_[attribute]!`
*Renato Mascarenhas*
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index b713e99e25..963e52bff3 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -328,19 +328,6 @@ module ActiveModel
end
end
- # Will add an error message to each of the attributes in +attributes+ that
- # is present (using Object#present?).
- #
- # person.errors.add_on_present(:name)
- # person.errors.messages
- # # => { :name => ["must be blank"] }
- def add_on_present(attributes, options = {})
- Array(attributes).flatten.each do |attribute|
- value = @base.send(:read_attribute_for_validation, attribute)
- add(attribute, :not_blank, options) if value.present?
- end
- end
-
# Returns +true+ if an error on the attribute with the given message is
# present, +false+ otherwise. +message+ is treated the same as for +add+.
#
diff --git a/activemodel/lib/active_model/locale/en.yml b/activemodel/lib/active_model/locale/en.yml
index 8ea34b84f5..540e8132d3 100644
--- a/activemodel/lib/active_model/locale/en.yml
+++ b/activemodel/lib/active_model/locale/en.yml
@@ -13,7 +13,7 @@ en:
accepted: "must be accepted"
empty: "can't be empty"
blank: "can't be blank"
- not_blank: "must be blank"
+ present: "must be blank"
too_long: "is too long (maximum is %{count} characters)"
too_short: "is too short (minimum is %{count} characters)"
wrong_length: "is the wrong length (should be %{count} characters)"
diff --git a/activemodel/lib/active_model/validations/absence.rb b/activemodel/lib/active_model/validations/absence.rb
index 6790554907..1a1863370b 100644
--- a/activemodel/lib/active_model/validations/absence.rb
+++ b/activemodel/lib/active_model/validations/absence.rb
@@ -2,8 +2,8 @@ module ActiveModel
module Validations
# == Active Model Absence Validator
class AbsenceValidator < EachValidator #:nodoc:
- def validate(record)
- record.errors.add_on_present(attributes, options)
+ def validate_each(record, attr_name, value)
+ record.errors.add(attr_name, :present, options) if value.present?
end
end
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index ff3dfa01c8..d51f4d1936 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -110,7 +110,7 @@ module ActiveModel
# Return the kind for this validator.
#
# PresenceValidator.new.kind # => :presence
- # UniquenessValidator.new.kind # => :uniqueness
+ # UniquenessValidator.new.kind # => :uniqueness
def kind
self.class.kind
end
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index f9684b0bcd..c602ca5eac 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -106,7 +106,7 @@ class Insure
def self.load mask
INSURES.select do |insure|
- (1 << INSURES.index(insure)) & mask > 0
+ (1 << INSURES.index(insure)) & mask.to_i > 0
end
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 1d11ae2afd..41fde553fb 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,14 @@
## Rails 4.0.0 (unreleased) ##
+* Prevent `Callbacks#set_callback` from setting the same callback twice.
+
+ before_save :foo, :bar, :foo
+
+ will at first call `bar`, then `foo`. `foo` will no more be called
+ twice.
+
+ *Dmitriy Kiriyenko*
+
* Add ActiveSupport::Logger#silence that works the same as the old Logger#silence extension.
*DHH*
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index e772a297fc..e3e1845868 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -134,6 +134,10 @@ module ActiveSupport
@kind == _kind && @filter == _filter
end
+ def duplicates?(other)
+ matches?(other.kind, other.filter)
+ end
+
def _update_filter(filter_options, new_options)
filter_options[:if].concat(Array(new_options[:unless])) if new_options.key?(:unless)
filter_options[:unless].concat(Array(new_options[:if])) if new_options.key?(:if)
@@ -328,6 +332,30 @@ module ActiveSupport
method.join("\n")
end
+ def append(*callbacks)
+ callbacks.each { |c| append_one(c) }
+ end
+
+ def prepend(*callbacks)
+ callbacks.each { |c| prepend_one(c) }
+ end
+
+ private
+
+ def append_one(callback)
+ remove_duplicates(callback)
+ push(callback)
+ end
+
+ def prepend_one(callback)
+ remove_duplicates(callback)
+ unshift(callback)
+ end
+
+ def remove_duplicates(callback)
+ delete_if { |c| callback.duplicates?(c) }
+ end
+
end
module ClassMethods
@@ -421,11 +449,7 @@ module ActiveSupport
Callback.new(chain, filter, type, options.dup, self)
end
- filters.each do |filter|
- chain.delete_if {|c| c.matches?(type, filter) }
- end
-
- options[:prepend] ? chain.unshift(*(mapped.reverse)) : chain.push(*mapped)
+ options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
target.send("_#{name}_callbacks=", chain)
end
diff --git a/activesupport/lib/active_support/core_ext/logger.rb b/activesupport/lib/active_support/core_ext/logger.rb
index 36c8f241b2..34de766331 100644
--- a/activesupport/lib/active_support/core_ext/logger.rb
+++ b/activesupport/lib/active_support/core_ext/logger.rb
@@ -32,7 +32,7 @@ require 'logger'
#
# logger.datetime_format = "%Y-%m-%d"
#
-# Note: This logger is deprecated in favor of ActiveSupport::BufferedLogger
+# Note: This logger is deprecated in favor of ActiveSupport::Logger
class Logger
include LoggerSilence
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 8810302f40..13f2e3cdaf 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -297,7 +297,7 @@ module CallbacksTest
end
end
end
-
+
class AroundPersonResult < MySuper
attr_reader :result
@@ -308,7 +308,7 @@ module CallbacksTest
def tweedle_dum
@result = yield
end
-
+
def tweedle_1
:tweedle_1
end
@@ -316,7 +316,7 @@ module CallbacksTest
def tweedle_2
:tweedle_2
end
-
+
def save
run_callbacks :save do
:running
@@ -410,7 +410,7 @@ module CallbacksTest
], around.history
end
end
-
+
class AroundCallbackResultTest < ActiveSupport::TestCase
def test_save_around
around = AroundPersonResult.new
@@ -607,6 +607,45 @@ module CallbacksTest
end
end
+ class OneTwoThreeSave
+ include ActiveSupport::Callbacks
+
+ define_callbacks :save
+
+ attr_accessor :record
+
+ def initialize
+ @record = []
+ end
+
+ def save
+ run_callbacks :save do
+ @record << "yielded"
+ end
+ end
+
+ def first
+ @record << "one"
+ end
+
+ def second
+ @record << "two"
+ end
+
+ def third
+ @record << "three"
+ end
+ end
+
+ class DuplicatingCallbacks < OneTwoThreeSave
+ set_callback :save, :before, :first, :second
+ set_callback :save, :before, :first, :third
+ end
+
+ class DuplicatingCallbacksInSameCall < OneTwoThreeSave
+ set_callback :save, :before, :first, :second, :first, :third
+ end
+
class UsingObjectTest < ActiveSupport::TestCase
def test_before_object
u = UsingObjectBefore.new
@@ -709,5 +748,18 @@ module CallbacksTest
end
end
end
-
+
+ class ExcludingDuplicatesCallbackTest < ActiveSupport::TestCase
+ def test_excludes_duplicates_in_separate_calls
+ model = DuplicatingCallbacks.new
+ model.save
+ assert_equal ["two", "one", "three", "yielded"], model.record
+ end
+
+ def test_excludes_duplicates_in_one_call
+ model = DuplicatingCallbacksInSameCall.new
+ model.save
+ assert_equal ["two", "one", "three", "yielded"], model.record
+ end
+ end
end
diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb
index 9516556844..d6821135ea 100644
--- a/activesupport/test/test_test.rb
+++ b/activesupport/test/test_test.rb
@@ -122,12 +122,12 @@ end
# Setup and teardown callbacks.
class SetupAndTeardownTest < ActiveSupport::TestCase
setup :reset_callback_record, :foo
- teardown :foo, :sentinel, :foo
+ teardown :foo, :sentinel
def test_inherited_setup_callbacks
assert_equal [:reset_callback_record, :foo], self.class._setup_callbacks.map(&:raw_filter)
assert_equal [:foo], @called_back
- assert_equal [:foo, :sentinel, :foo], self.class._teardown_callbacks.map(&:raw_filter)
+ assert_equal [:foo, :sentinel], self.class._teardown_callbacks.map(&:raw_filter)
end
def setup
@@ -147,7 +147,7 @@ class SetupAndTeardownTest < ActiveSupport::TestCase
end
def sentinel
- assert_equal [:foo, :foo], @called_back
+ assert_equal [:foo], @called_back
end
end
@@ -159,7 +159,7 @@ class SubclassSetupAndTeardownTest < SetupAndTeardownTest
def test_inherited_setup_callbacks
assert_equal [:reset_callback_record, :foo, :bar], self.class._setup_callbacks.map(&:raw_filter)
assert_equal [:foo, :bar], @called_back
- assert_equal [:foo, :sentinel, :foo, :bar], self.class._teardown_callbacks.map(&:raw_filter)
+ assert_equal [:foo, :sentinel, :bar], self.class._teardown_callbacks.map(&:raw_filter)
end
protected
@@ -168,7 +168,7 @@ class SubclassSetupAndTeardownTest < SetupAndTeardownTest
end
def sentinel
- assert_equal [:foo, :bar, :bar, :foo], @called_back
+ assert_equal [:foo, :bar, :bar], @called_back
end
end
diff --git a/guides/source/security.md b/guides/source/security.md
index 8096ea2383..0b0cfe69c4 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -94,16 +94,15 @@ Rails 2 introduced a new default session storage, CookieStore. CookieStore saves
* The client can see everything you store in a session, because it is stored in clear-text (actually Base64-encoded, so not encrypted). So, of course, _you don't want to store any secrets here_. To prevent session hash tampering, a digest is calculated from the session with a server-side secret and inserted into the end of the cookie.
-That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA512, which has not been compromised, yet). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters_. Put the secret in your environment.rb:
+That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA512, which has not been compromised, yet). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters_.
-```ruby
-config.action_dispatch.session = {
- key: '_app_session',
- secret: '0x0dkfj3927dkc7djdh36rkckdfzsg...'
-}
-```
+`config.secret_key_base` is used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `config.secret_key_base` initialized to a random key in `config/initializers/secret_token.rb`, e.g.:
+
+ YourApp::Application.config.secret_key_base = '49d3f3de9ed86c74b94ad6bd0...'
-There are, however, derivatives of CookieStore which encrypt the session hash, so the client cannot see it.
+Older versions of Rails use CookieStore, which uses `secret_token` instead of `secret_key_base` that is used by EncryptedCookieStore. Read the upgrade documentation for more information.
+
+If you have received an application where the secret was exposed (e.g. an application whose source was shared), strongly consider changing the secret.
### Replay Attacks for CookieStore Sessions
@@ -959,6 +958,11 @@ Used to control which sites are allowed to bypass same origin policies and send
* Strict-Transport-Security
[Used to control if the browser is allowed to only access a site over a secure connection](http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security)
+Environmental Security
+----------------------
+
+It is beyond the scope of this guide to inform you on how to secure your application code and environments. However, please secure your database configuration, e.g. `config/database.yml`, and your server-side secret, e.g. stored in `config/initializers/secret_token.rb`. You may want to further restrict access, using environment-specific versions of these files and any others that may contain sensitive information.
+
Additional Resources
--------------------