diff options
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/CHANGELOG.md | 4 | ||||
-rw-r--r-- | activemodel/activemodel.gemspec | 14 | ||||
-rw-r--r-- | activemodel/lib/active_model/errors.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/forbidden_attributes_protection.rb | 2 | ||||
-rw-r--r-- | activemodel/lib/active_model/naming.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/railtie.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/secure_password.rb | 5 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/validates.rb | 2 | ||||
-rw-r--r-- | activemodel/lib/active_model/validator.rb | 2 | ||||
-rw-r--r-- | activemodel/test/cases/errors_test.rb | 40 | ||||
-rw-r--r-- | activemodel/test/cases/railtie_test.rb | 28 | ||||
-rw-r--r-- | activemodel/test/cases/secure_password_test.rb | 13 | ||||
-rw-r--r-- | activemodel/test/cases/validations/i18n_validation_test.rb | 20 | ||||
-rw-r--r-- | activemodel/test/cases/validations/with_validation_test.rb | 2 |
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 |