aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel')
-rw-r--r--activemodel/CHANGELOG.md4
-rw-r--r--activemodel/activemodel.gemspec14
-rw-r--r--activemodel/lib/active_model/errors.rb4
-rw-r--r--activemodel/lib/active_model/forbidden_attributes_protection.rb2
-rw-r--r--activemodel/lib/active_model/naming.rb4
-rw-r--r--activemodel/lib/active_model/railtie.rb4
-rw-r--r--activemodel/lib/active_model/secure_password.rb5
-rw-r--r--activemodel/lib/active_model/validations/validates.rb2
-rw-r--r--activemodel/lib/active_model/validator.rb2
-rw-r--r--activemodel/test/cases/errors_test.rb40
-rw-r--r--activemodel/test/cases/railtie_test.rb28
-rw-r--r--activemodel/test/cases/secure_password_test.rb13
-rw-r--r--activemodel/test/cases/validations/i18n_validation_test.rb20
-rw-r--r--activemodel/test/cases/validations/with_validation_test.rb2
14 files changed, 107 insertions, 37 deletions
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index aa42bf762f..133bb558a9 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ##
+* Use BCrypt's MIN_COST in the test environment for speedier tests when using `has_secure_pasword`.
+
+ *Brian Cardarella + Jeremy Kemper + Trevor Turk*
+
* Add `ActiveModel::ForbiddenAttributesProtection`, a simple module to
protect attributes from mass assignment when non-permitted attributes are passed.
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index be5d5d3ca8..51655fe3da 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -8,15 +8,17 @@ Gem::Specification.new do |s|
s.description = 'A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, observers, serialization, internationalization, and testing.'
s.required_ruby_version = '>= 1.9.3'
- s.license = 'MIT'
- s.author = 'David Heinemeier Hansson'
- s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.license = 'MIT'
+
+ s.author = 'David Heinemeier Hansson'
+ s.email = 'david@loudthinking.com'
+ s.homepage = 'http://www.rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*']
s.require_path = 'lib'
- s.add_dependency('activesupport', version)
- s.add_dependency('builder', '~> 3.1.0')
+ s.add_dependency 'activesupport', version
+
+ s.add_dependency 'builder', '~> 3.1.0'
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 6882b59e26..c82d4f012c 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -308,7 +308,7 @@ module ActiveModel
# person.errors.messages
# # => {:name=>["can't be empty"]}
def add_on_empty(attributes, options = {})
- [attributes].flatten.each do |attribute|
+ Array(attributes).each do |attribute|
value = @base.send(:read_attribute_for_validation, attribute)
is_empty = value.respond_to?(:empty?) ? value.empty? : false
add(attribute, :empty, options) if value.nil? || is_empty
@@ -322,7 +322,7 @@ module ActiveModel
# person.errors.messages
# # => {:name=>["can't be blank"]}
def add_on_blank(attributes, options = {})
- [attributes].flatten.each do |attribute|
+ Array(attributes).each do |attribute|
value = @base.send(:read_attribute_for_validation, attribute)
add(attribute, :blank, options) if value.blank?
end
diff --git a/activemodel/lib/active_model/forbidden_attributes_protection.rb b/activemodel/lib/active_model/forbidden_attributes_protection.rb
index 4c05b19cba..7468f95548 100644
--- a/activemodel/lib/active_model/forbidden_attributes_protection.rb
+++ b/activemodel/lib/active_model/forbidden_attributes_protection.rb
@@ -16,7 +16,7 @@ module ActiveModel
module ForbiddenAttributesProtection # :nodoc:
protected
- def sanitize_for_mass_assignment(attributes, options = {})
+ def sanitize_for_mass_assignment(attributes)
if attributes.respond_to?(:permitted?) && !attributes.permitted?
raise ActiveModel::ForbiddenAttributesError
else
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index eb8265d8c6..264880eecd 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -263,10 +263,10 @@ module ActiveModel
# namespaced models regarding whether it's inside isolated engine.
#
# # For isolated engine:
- # ActiveModel::Naming.route_key(Blog::Post) #=> post
+ # ActiveModel::Naming.singular_route_key(Blog::Post) #=> post
#
# # For shared engine:
- # ActiveModel::Naming.route_key(Blog::Post) #=> blog_post
+ # ActiveModel::Naming.singular_route_key(Blog::Post) #=> blog_post
def self.singular_route_key(record_or_class)
model_name_from_record_or_class(record_or_class).singular_route_key
end
diff --git a/activemodel/lib/active_model/railtie.rb b/activemodel/lib/active_model/railtie.rb
index 75cde900e3..1671eb7bd4 100644
--- a/activemodel/lib/active_model/railtie.rb
+++ b/activemodel/lib/active_model/railtie.rb
@@ -4,5 +4,9 @@ require "rails"
module ActiveModel
class Railtie < Rails::Railtie # :nodoc:
config.eager_load_namespaces << ActiveModel
+
+ initializer "active_model.secure_password" do
+ ActiveModel::SecurePassword.min_cost = Rails.env.test?
+ end
end
end
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index f19c836bea..081a49f749 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -2,6 +2,8 @@ module ActiveModel
module SecurePassword
extend ActiveSupport::Concern
+ class << self; attr_accessor :min_cost; end
+
module ClassMethods
# Adds methods to set and authenticate against a BCrypt password.
# This mechanism requires you to have a password_digest attribute.
@@ -92,7 +94,8 @@ module ActiveModel
def password=(unencrypted_password)
unless unencrypted_password.blank?
@password = unencrypted_password
- self.password_digest = BCrypt::Password.create(unencrypted_password)
+ cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine::DEFAULT_COST
+ self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost)
end
end
end
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index 4651154934..1eb0716891 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -104,7 +104,7 @@ module ActiveModel
raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
raise ArgumentError, "You need to supply at least one validation" if validations.empty?
- defaults.merge!(:attributes => attributes)
+ defaults[:attributes] = attributes
validations.each do |key, options|
next unless options
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index c795dc9dcd..629b157fed 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -135,7 +135,7 @@ module ActiveModel
# and instead be made available through the +attributes+ reader.
def initialize(options)
@attributes = Array(options.delete(:attributes))
- raise ":attributes cannot be blank" if @attributes.empty?
+ raise ArgumentError, ":attributes cannot be blank" if @attributes.empty?
super
check_validity!
end
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index 3bc0d58351..293ce07f4e 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -7,7 +7,7 @@ class ErrorsTest < ActiveModel::TestCase
@errors = ActiveModel::Errors.new(self)
end
- attr_accessor :name
+ attr_accessor :name, :age
attr_reader :errors
def validate!
@@ -201,5 +201,43 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.generate_message(:name, :blank)
}
end
+
+ test "add_on_empty generates message" do
+ person = Person.new
+ person.errors.expects(:generate_message).with(:name, :empty, {})
+ person.errors.add_on_empty :name
+ end
+
+ test "add_on_empty generates message for multiple attributes" do
+ person = Person.new
+ person.errors.expects(:generate_message).with(:name, :empty, {})
+ person.errors.expects(:generate_message).with(:age, :empty, {})
+ person.errors.add_on_empty [:name, :age]
+ end
+
+ test "add_on_empty generates message with custom default message" do
+ person = Person.new
+ person.errors.expects(:generate_message).with(:name, :empty, {:message => 'custom'})
+ person.errors.add_on_empty :name, :message => 'custom'
+ end
+
+ test "add_on_blank generates message" do
+ person = Person.new
+ person.errors.expects(:generate_message).with(:name, :blank, {})
+ person.errors.add_on_blank :name
+ end
+
+ test "add_on_blank generates message for multiple attributes" do
+ person = Person.new
+ person.errors.expects(:generate_message).with(:name, :blank, {})
+ person.errors.expects(:generate_message).with(:age, :blank, {})
+ person.errors.add_on_blank [:name, :age]
+ end
+
+ test "add_on_blank generates message with custom default message" do
+ person = Person.new
+ person.errors.expects(:generate_message).with(:name, :blank, {:message => 'custom'})
+ person.errors.add_on_blank :name, :message => 'custom'
+ end
end
diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb
new file mode 100644
index 0000000000..f89a288f8f
--- /dev/null
+++ b/activemodel/test/cases/railtie_test.rb
@@ -0,0 +1,28 @@
+require 'cases/helper'
+require 'active_support/testing/isolation'
+
+class RailtieTest < ActiveModel::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ require 'rails/all'
+
+ @app ||= Class.new(::Rails::Application).tap do |app|
+ app.config.eager_load = false
+ end
+ end
+
+ test 'secure password min_cost is false in the development environment' do
+ Rails.env = 'development'
+ @app.initialize!
+
+ assert_equal false, ActiveModel::SecurePassword.min_cost
+ end
+
+ test 'secure password min_cost is true in the test environment' do
+ Rails.env = 'test'
+ @app.initialize!
+
+ assert_equal true, ActiveModel::SecurePassword.min_cost
+ end
+end
diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb
index 509e2fdbb5..c7e93370ec 100644
--- a/activemodel/test/cases/secure_password_test.rb
+++ b/activemodel/test/cases/secure_password_test.rb
@@ -63,10 +63,21 @@ class SecurePasswordTest < ActiveModel::TestCase
@user.run_callbacks :create
end
end
-
+
test "Oauthed user can be created with blank digest" do
assert_nothing_raised do
@oauthed_user.run_callbacks :create
end
end
+
+ test "Password digest cost defaults to bcrypt default cost" do
+ @user.password = "secret"
+ assert_equal BCrypt::Engine::DEFAULT_COST, @user.password_digest.cost
+ end
+
+ test "Password digest cost can be set to bcrypt min cost to speed up tests" do
+ ActiveModel::SecurePassword.min_cost = true
+ @user.password = "secret"
+ assert_equal BCrypt::Engine::MIN_COST, @user.password_digest.cost
+ end
end
diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb
index 4f8b7327c0..4c01b47608 100644
--- a/activemodel/test/cases/validations/i18n_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_validation_test.rb
@@ -21,26 +21,6 @@ class I18nValidationTest < ActiveModel::TestCase
I18n.backend = @old_backend
end
- def test_errors_add_on_empty_generates_message
- @person.errors.expects(:generate_message).with(:title, :empty, {})
- @person.errors.add_on_empty :title
- end
-
- def test_errors_add_on_empty_generates_message_with_custom_default_message
- @person.errors.expects(:generate_message).with(:title, :empty, {:message => 'custom'})
- @person.errors.add_on_empty :title, :message => 'custom'
- end
-
- def test_errors_add_on_blank_generates_message
- @person.errors.expects(:generate_message).with(:title, :blank, {})
- @person.errors.add_on_blank :title
- end
-
- def test_errors_add_on_blank_generates_message_with_custom_default_message
- @person.errors.expects(:generate_message).with(:title, :blank, {:message => 'custom'})
- @person.errors.add_on_blank :title, :message => 'custom'
- end
-
def test_full_message_encoding
I18n.backend.store_translations('en', :errors => {
:messages => { :too_short => '猫舌' }})
diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb
index 07c1bd0533..457f553661 100644
--- a/activemodel/test/cases/validations/with_validation_test.rb
+++ b/activemodel/test/cases/validations/with_validation_test.rb
@@ -151,7 +151,7 @@ class ValidatesWithTest < ActiveModel::TestCase
end
test "each validator expects attributes to be given" do
- assert_raise RuntimeError do
+ assert_raise ArgumentError do
Topic.validates_with(ValidatorPerEachAttribute)
end
end