diff options
author | Ryan Garver <ragarver@gmail.com> | 2012-10-04 08:13:12 -0700 |
---|---|---|
committer | Ryan Garver <ragarver@gmail.com> | 2012-10-04 08:13:12 -0700 |
commit | 1f3a8c873ed9b3fc8eb41ae775a570b95ebdf715 (patch) | |
tree | 7dad02bf5f727d327fae9ccac1c2007dc4641be1 | |
parent | 4cb50a3f571234b1202f9a0dffe39b445ecf807d (diff) | |
parent | d7d228402efd1ddbbdb2b15d2e91ec22693b9298 (diff) | |
download | rails-1f3a8c873ed9b3fc8eb41ae775a570b95ebdf715.tar.gz rails-1f3a8c873ed9b3fc8eb41ae775a570b95ebdf715.tar.bz2 rails-1f3a8c873ed9b3fc8eb41ae775a570b95ebdf715.zip |
Merge branch 'master' into feature/public-fragment_name_with_digest
-rw-r--r-- | activemodel/lib/active_model/validations.rb | 4 | ||||
-rw-r--r-- | activerecord/CHANGELOG.md | 17 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/collection_association.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/counter_cache.rb | 9 | ||||
-rw-r--r-- | activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb | 6 | ||||
-rw-r--r-- | activerecord/test/cases/associations/has_many_associations_test.rb | 6 | ||||
-rw-r--r-- | activerecord/test/cases/associations/has_many_through_associations_test.rb | 6 | ||||
-rw-r--r-- | activesupport/lib/active_support.rb | 1 | ||||
-rw-r--r-- | activesupport/lib/active_support/key_generator.rb | 23 | ||||
-rw-r--r-- | activesupport/test/key_generator_test.rb | 32 | ||||
-rw-r--r-- | railties/CHANGELOG.md | 2 | ||||
-rw-r--r-- | railties/lib/rails.rb | 2 | ||||
-rw-r--r-- | railties/lib/rails/application.rb | 11 | ||||
-rw-r--r-- | railties/test/application/configuration_test.rb | 11 |
14 files changed, 122 insertions, 10 deletions
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 4762f39044..243d911f71 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -188,9 +188,9 @@ module ActiveModel # # #<ActiveModel::Validations::InclusionValidator:0x007fe603bb8780 @attributes=[:age], @options={:in=>0..99}> # # ] def validators_on(*attributes) - attributes.map do |attribute| + attributes.flat_map do |attribute| _validators[attribute.to_sym] - end.flatten + end end # Returns +true+ if +attribute+ is an attribute method, +false+ otherwise. diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 8ff4c4706c..714263faea 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,22 @@ ## Rails 4.0.0 (unreleased) ## +* `CollectionAssociation#count` returns `0` without querying if the + parent record is not persisted. + + Before: + + person.pets.count + # SELECT COUNT(*) FROM "pets" WHERE "pets"."person_id" IS NULL + # => 0 + + After: + + person.pets.count + # fires without sql query + # => 0 + + *Francesco Rodriguez* + * Fix `reset_counters` crashing on `has_many :through` associations. Fix #7822. diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index fe3e5b00f7..96270ec0e9 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -174,6 +174,8 @@ module ActiveRecord # association, it will be used for the query. Otherwise, construct options and pass them with # scope to the target class's +count+. def count(column_name = nil, count_options = {}) + return 0 if owner.new_record? + column_name, count_options = nil, column_name if column_name.is_a?(Hash) if options[:counter_sql] || options[:finder_sql] diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb index d28cd560d9..57838ff984 100644 --- a/activerecord/lib/active_record/counter_cache.rb +++ b/activerecord/lib/active_record/counter_cache.rb @@ -23,12 +23,11 @@ module ActiveRecord has_many_association = reflect_on_association(association.to_sym) if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection - foreign_key = has_many_association.through_reflection.foreign_key.to_s - child_class = has_many_association.through_reflection.klass - else - foreign_key = has_many_association.foreign_key.to_s - child_class = has_many_association.klass + has_many_association = has_many_association.through_reflection end + + foreign_key = has_many_association.foreign_key.to_s + child_class = has_many_association.klass belongs_to = child_class.reflect_on_all_associations(:belongs_to) reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? } counter_name = reflection.counter_cache_column diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index f3520d43e0..42f5b69d4e 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -799,6 +799,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, developer.projects.count end + def test_counting_should_not_fire_sql_if_parent_is_unsaved + assert_no_queries do + assert_equal 0, Developer.new.projects.count + end + end + unless current_adapter?(:PostgreSQLAdapter) def test_count_with_finder_sql assert_equal 3, projects(:active_record).developers_with_finder_sql.count diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 4b56037a08..50c23c863f 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -262,6 +262,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal firm.limited_clients.length, firm.limited_clients.count end + def test_counting_should_not_fire_sql_if_parent_is_unsaved + assert_no_queries do + assert_equal 0, Person.new.readers.count + end + end + def test_finding assert_equal 2, Firm.all.merge!(:order => "id").first.clients.length end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index d4ceae6f80..f0582a3090 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -767,6 +767,12 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal 1, authors(:mary).categories.general.count end + def test_counting_should_not_fire_sql_if_parent_is_unsaved + assert_no_queries do + assert_equal 0, Person.new.posts.count + end + end + def test_has_many_through_belongs_to_should_update_when_the_through_foreign_key_changes post = posts(:eager_other) diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 41d77ab6c1..4e397ea110 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -48,6 +48,7 @@ module ActiveSupport autoload :Gzip autoload :Inflector autoload :JSON + autoload :KeyGenerator autoload :MessageEncryptor autoload :MessageVerifier autoload :Multibyte diff --git a/activesupport/lib/active_support/key_generator.rb b/activesupport/lib/active_support/key_generator.rb new file mode 100644 index 0000000000..04d170f801 --- /dev/null +++ b/activesupport/lib/active_support/key_generator.rb @@ -0,0 +1,23 @@ +require 'openssl' + +module ActiveSupport + # KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2 + # It can be used to derive a number of keys for various purposes from a given secret. + # This lets rails applications have a single secure secret, but avoid reusing that + # key in multiple incompatible contexts. + class KeyGenerator + def initialize(secret, options = {}) + @secret = secret + # The default iterations are higher than required for our key derivation uses + # on the off chance someone uses this for password storage + @iterations = options[:iterations] || 2**16 + end + + # Returns a derived key suitable for use. The default key_size is chosen + # to be compatible with the default settings of ActiveSupport::MessageVerifier. + # i.e. OpenSSL::Digest::SHA1#block_length + def generate_key(salt, key_size=64) + OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, @iterations, key_size) + end + end +end diff --git a/activesupport/test/key_generator_test.rb b/activesupport/test/key_generator_test.rb new file mode 100644 index 0000000000..525082d313 --- /dev/null +++ b/activesupport/test/key_generator_test.rb @@ -0,0 +1,32 @@ +require 'abstract_unit' + +begin + require 'openssl' + OpenSSL::PKCS5 +rescue LoadError, NameError + $stderr.puts "Skipping KeyGenerator test: broken OpenSSL install" +else + +require 'active_support/time' +require 'active_support/json' + +class KeyGeneratorTest < ActiveSupport::TestCase + def setup + @secret = SecureRandom.hex(64) + @generator = ActiveSupport::KeyGenerator.new(@secret, :iterations=>2) + end + + test "Generating a key of the default length" do + derived_key = @generator.generate_key("some_salt") + assert_kind_of String, derived_key + assert_equal OpenSSL::Digest::SHA1.new.block_length, derived_key.length, "Should have generated a key of the default size" + end + + test "Generating a key of an alternative length" do + derived_key = @generator.generate_key("some_salt", 32) + assert_kind_of String, derived_key + assert_equal 32, derived_key.length, "Should have generated a key of the right size" + end +end + +end diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 8c2b64d543..a422c5fe39 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* `Rails.public_path` now returns a Pathname object. *Prem Sichanugrist* + * Remove highly uncommon `config.assets.manifest` option for moving the manifest path. This option is now unsupported in sprockets-rails. diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index a15965a9da..d7e22cc839 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -127,7 +127,7 @@ module Rails end def public_path - application && application.paths["public"].first + application && Pathname.new(application.paths["public"].first) end end end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 0b9ed025db..c8a6600da9 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -101,6 +101,14 @@ module Rails routes_reloader.reload! end + + # Return the application's KeyGenerator + def key_generator + # number of iterations selected based on consultation with the google security + # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220 + @key_generator ||= ActiveSupport::KeyGenerator.new(config.secret_token, :iterations=>1000) + end + # Stores some of the Rails initial environment parameters which # will be used by middlewares and engines to configure themselves. # Currently stores: @@ -121,7 +129,8 @@ module Rails "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, "action_dispatch.logger" => Rails.logger, - "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner + "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner, + "action_dispatch.key_generator" => key_generator }) end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index d014e5e362..ac41e01616 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -139,6 +139,14 @@ module ApplicationTests assert_instance_of Pathname, Rails.root end + test "Rails.public_path should be a Pathname" do + add_to_config <<-RUBY + config.paths["public"] = "somewhere" + RUBY + require "#{app_path}/config/environment" + assert_instance_of Pathname, Rails.public_path + end + test "initialize an eager loaded, cache classes app" do add_to_config <<-RUBY config.eager_load = true @@ -227,7 +235,7 @@ module ApplicationTests RUBY require "#{app_path}/config/application" - assert_equal File.join(app_path, "somewhere"), Rails.public_path + assert_equal Pathname.new(app_path).join("somewhere"), Rails.public_path end test "config.secret_token is sent in env" do @@ -634,6 +642,7 @@ module ApplicationTests assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions assert_equal app.env_config['action_dispatch.logger'], Rails.logger assert_equal app.env_config['action_dispatch.backtrace_cleaner'], Rails.backtrace_cleaner + assert_equal app.env_config['action_dispatch.key_generator'], Rails.application.key_generator end test "config.colorize_logging default is true" do |