diff options
37 files changed, 237 insertions, 178 deletions
diff --git a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb index 094ec85114..83f8a67da7 100644 --- a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb +++ b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb @@ -8,7 +8,9 @@ module Rails def create_mailer_file template "mailer.rb", File.join('app/mailers', class_path, "#{file_name}.rb") - template "application_mailer.rb", 'app/mailers/application_mailer.rb' + if self.behavior == :invoke + template "application_mailer.rb", 'app/mailers/application_mailer.rb' + end end hook_for :template_engine, :test_framework diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index 1e13b3761f..7590fb6843 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -189,12 +189,6 @@ module ActionController !@aborted end - def await_close - synchronize do - @cv.wait_until { @closed } - end - end - def on_error(&block) @error_callback = block end diff --git a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb index e65f7238ab..0ccab21801 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb @@ -45,51 +45,6 @@ module ActionDispatch (@table.keys + @table.values.flat_map(&:keys)).uniq end - # Returns a generalized transition graph with reduced states. The states - # are reduced like a DFA, but the table must be simulated like an NFA. - # - # Edges of the GTG are regular expressions. - def generalized_table - gt = GTG::TransitionTable.new - marked = {} - state_id = Hash.new { |h,k| h[k] = h.length } - alphabet = self.alphabet - - stack = [eclosure(0)] - - until stack.empty? - state = stack.pop - next if marked[state] || state.empty? - - marked[state] = true - - alphabet.each do |alpha| - next_state = eclosure(following_states(state, alpha)) - next if next_state.empty? - - gt[state_id[state], state_id[next_state]] = alpha - stack << next_state - end - end - - final_groups = state_id.keys.find_all { |s| - s.sort.last == accepting - } - - final_groups.each do |states| - id = state_id[states] - - gt.add_accepting(id) - save = states.find { |s| - @memos.key?(s) && eclosure(s).sort.last == accepting - } - - gt.add_memo(id, memo(save)) - end - - gt - end - # Returns set of NFA states to which there is a transition on ast symbol # +a+ from some state +s+ in +t+. def following_states(t, a) diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb index 3b609a184d..4d5c18984a 100644 --- a/actionpack/lib/action_dispatch/journey/route.rb +++ b/actionpack/lib/action_dispatch/journey/route.rb @@ -68,10 +68,6 @@ module ActionDispatch @path_formatter.evaluate path_options end - def optional_parts - path.optional_names.map(&:to_sym) - end - def required_parts @required_parts ||= path.required_names.map(&:to_sym) end diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index c9fff081d6..93d1d33f78 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -283,7 +283,7 @@ module ActionDispatch def handle_options(options) #:nodoc: options[:path] ||= "/" - if options[:domain] == :all + if options[:domain] == :all || options[:domain] == 'all' # if there is a provided tld length then we use it otherwise default domain regexp domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb index 27871ef351..2be947c648 100644 --- a/actionpack/test/controller/localized_templates_test.rb +++ b/actionpack/test/controller/localized_templates_test.rb @@ -19,7 +19,7 @@ class LocalizedTemplatesTest < ActionController::TestCase def test_localized_template_is_used I18n.locale = :de get :hello_world - assert_equal "Gutten Tag", @response.body + assert_equal "Guten Tag", @response.body end def test_default_locale_template_is_used_when_locale_is_missing @@ -34,7 +34,7 @@ class LocalizedTemplatesTest < ActionController::TestCase I18n.fallbacks[:"de-AT"] = [:de] get :hello_world - assert_equal "Gutten Tag", @response.body + assert_equal "Guten Tag", @response.body end def test_localized_template_has_correct_header_with_no_format_in_template_name diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index 5be75a5de6..19a98a4054 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -1,12 +1,5 @@ require 'abstract_unit' - -begin - require 'openssl' - OpenSSL::PKCS5 -rescue LoadError, NameError - $stderr.puts "Skipping KeyGenerator test: broken OpenSSL install" -else - +require 'openssl' require 'active_support/key_generator' require 'active_support/message_verifier' @@ -152,11 +145,21 @@ class CookiesTest < ActionController::TestCase head :ok end + def set_cookie_with_domain_all_as_string + cookies[:user_name] = {:value => "rizwanreza", :domain => 'all'} + head :ok + end + def delete_cookie_with_domain cookies.delete(:user_name, :domain => :all) head :ok end + def delete_cookie_with_domain_all_as_string + cookies.delete(:user_name, :domain => 'all') + head :ok + end + def set_cookie_with_domain_and_tld cookies[:user_name] = {:value => "rizwanreza", :domain => :all, :tld_length => 2} head :ok @@ -1155,5 +1158,3 @@ class CookiesTest < ActionController::TestCase end end end - -end diff --git a/actionpack/test/fixtures/localized/hello_world.de.html b/actionpack/test/fixtures/localized/hello_world.de.html index 4727d7a7e0..a8fc612c60 100644 --- a/actionpack/test/fixtures/localized/hello_world.de.html +++ b/actionpack/test/fixtures/localized/hello_world.de.html @@ -1 +1 @@ -Gutten Tag
\ No newline at end of file +Guten Tag
\ No newline at end of file diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb index 21d2fda3ff..cd29e6908e 100644 --- a/activejob/lib/active_job/logging.rb +++ b/activejob/lib/active_job/logging.rb @@ -85,7 +85,12 @@ module ActiveJob end def args_info(job) - job.arguments.any? ? " with arguments: #{job.arguments.map(&:inspect).join(", ")}" : "" + if job.arguments.any? + ' with arguments: ' + + job.arguments.map { |arg| arg.try(:to_global_id).try(:to_s) || arg.inspect }.join(', ') + else + '' + end end def scheduled_at(event) diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb index 3d4e561117..64aae00441 100644 --- a/activejob/test/cases/logging_test.rb +++ b/activejob/test/cases/logging_test.rb @@ -4,6 +4,7 @@ require 'active_support/core_ext/numeric/time' require 'jobs/hello_job' require 'jobs/logging_job' require 'jobs/nested_job' +require 'models/person' class AdapterTest < ActiveSupport::TestCase include ActiveSupport::LogSubscriber::TestHelper @@ -65,6 +66,14 @@ class AdapterTest < ActiveSupport::TestCase LoggingJob.queue_name = original_queue_name end + def test_globalid_parameter_logging + person = Person.new(123) + LoggingJob.perform_later person + assert_match(%r{Enqueued.*gid://aj/Person/123}, @logger.messages) + assert_match(%r{Dummy, here is it: #<Person:.*>}, @logger.messages) + assert_match(%r{Performing.*gid://aj/Person/123}, @logger.messages) + end + def test_enqueue_job_logging HelloJob.perform_later "Cristian" assert_match(/Enqueued HelloJob \(Job ID: .*?\) to .*?:.*Cristian/, @logger.messages) diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb index bdc61a1462..6ff18fb56a 100644 --- a/activejob/test/support/integration/adapters/sidekiq.rb +++ b/activejob/test/support/integration/adapters/sidekiq.rb @@ -48,7 +48,8 @@ module SidekiqJobsManager def can_run? begin - Sidekiq.redis(&:connect) + Sidekiq.redis(&:info) + Sidekiq.logger = nil rescue return false end diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index ea07c5c039..96be551264 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -353,14 +353,12 @@ module ActiveModel @attribute_method_matchers_cache ||= ThreadSafe::Cache.new(initial_capacity: 4) end - def attribute_method_matcher(method_name) #:nodoc: + def attribute_method_matchers_matching(method_name) #:nodoc: attribute_method_matchers_cache.compute_if_absent(method_name) do # Must try to match prefixes/suffixes first, or else the matcher with no prefix/suffix # will match every time. matchers = attribute_method_matchers.partition(&:plain?).reverse.flatten(1) - match = nil - matchers.detect { |method| match = method.match(method_name) } - match + matchers.map { |method| method.match(method_name) }.compact end end @@ -469,8 +467,8 @@ module ActiveModel # Returns a struct representing the matching attribute method. # The struct's attributes are prefix, base and suffix. def match_attribute_method?(method_name) - match = self.class.send(:attribute_method_matcher, method_name) - match if match && attribute_method?(match.attr_name) + matches = self.class.send(:attribute_method_matchers_matching, method_name) + matches.detect { |match| attribute_method?(match.attr_name) } end def missing_attribute(attr_name, stack) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 298ee21e01..152cbc751c 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,13 @@ +* Remove deprecated behavior allowing nested arrays to be passed as query + values. + + *Melanie Gilman* + +* Deprecate passing a class as a value in a query. Users should pass strings + instead. + + *Melanie Gilman* + * `add_timestamps` and `remove_timestamps` now properly reversible with options. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb index 35e699eeda..9b3de41fab 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb @@ -39,14 +39,14 @@ module ActiveRecord end def register_array_type(row) - if subtype = @store.lookup(row['typelem'].to_i) - register row['oid'], OID::Array.new(subtype, row['typdelim']) + register_with_subtype(row['oid'], row['typelem'].to_i) do |subtype| + OID::Array.new(subtype, row['typdelim']) end end def register_range_type(row) - if subtype = @store.lookup(row['rngsubtype'].to_i) - register row['oid'], OID::Range.new(subtype, row['typname'].to_sym) + register_with_subtype(row['oid'], row['rngsubtype'].to_i) do |subtype| + OID::Range.new(subtype, row['typname'].to_sym) end end @@ -64,9 +64,13 @@ module ActiveRecord end end - def register(oid, oid_type) - oid = assert_valid_registration(oid, oid_type) - @store.register_type(oid, oid_type) + def register(oid, oid_type = nil, &block) + oid = assert_valid_registration(oid, oid_type || block) + if block_given? + @store.register_type(oid, &block) + else + @store.register_type(oid, oid_type) + end end def alias_type(oid, target) @@ -74,6 +78,14 @@ module ActiveRecord @store.alias_type(oid, target) end + def register_with_subtype(oid, target_oid) + if @store.key?(target_oid) + register(oid) do |_, *args| + yield @store.lookup(target_oid, *args) + end + end + end + def assert_valid_registration(oid, oid_type) raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil? oid.to_i diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 3a60de1f28..6ef47d8a11 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -516,9 +516,12 @@ module ActiveRecord def extract_limit(sql_type) # :nodoc: case sql_type - when /^bigint/i; 8 - when /^smallint/i; 2 - else super + when /^bigint/i, /^int8/i + 8 + when /^smallint/i + 2 + else + super end end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index c812e7842a..c2d5582f02 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -85,7 +85,6 @@ module ActiveRecord mattr_accessor :dump_schema_after_migration, instance_writer: false self.dump_schema_after_migration = true - # :nodoc: mattr_accessor :maintain_test_schema, instance_accessor: false def self.disable_implicit_join_references=(value) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 6c09456c4d..4daf2a0e2b 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -240,7 +240,7 @@ db_namespace = namespace :db do end desc 'Load a schema.rb file into the database' - task :load => [:environment, :load_config] do + task :load => [:load_config] do ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA']) end diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index b069cdce7c..20d24b409b 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -40,8 +40,8 @@ module ActiveRecord # # NOTE: It's not possible to set the order. That is automatically set to # ascending on the primary key ("id ASC") to make the batch ordering - # work. This also means that this method only works with integer-based - # primary keys. + # work. This also means that this method only works when the primary key is + # orderable (e.g. an integer or string). # # NOTE: You can't set the limit either, that's used to control # the batch sizes. @@ -90,8 +90,8 @@ module ActiveRecord # # NOTE: It's not possible to set the order. That is automatically set to # ascending on the primary key ("id ASC") to make the batch ordering - # work. This also means that this method only works with integer-based - # primary keys. + # work. This also means that this method only works when the primary key is + # orderable (e.g. an integer or string). # # NOTE: You can't set the limit either, that's used to control # the batch sizes. diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index eb21d01465..67e646bf18 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -35,7 +35,7 @@ module ActiveRecord # PriceEstimate.where(estimate_of: treasure) if klass && reflection = klass._reflect_on_association(column) if reflection.polymorphic? && base_class = polymorphic_base_class_from_value(value) - queries << self.class.build(table[reflection.foreign_type], base_class) + queries << self.class.build(table[reflection.foreign_type], base_class.name) end column = reflection.foreign_key @@ -84,8 +84,7 @@ module ActiveRecord end register_handler(BasicObject, ->(attribute, value) { attribute.eq(value) }) - # FIXME: I think we need to deprecate this behavior - register_handler(Class, ->(attribute, value) { attribute.eq(value.name) }) + register_handler(Class, ->(attribute, value) { deprecate_class_handler; attribute.eq(value.name) }) register_handler(Base, ->(attribute, value) { attribute.eq(value.id) }) register_handler(Range, ->(attribute, value) { attribute.between(value) }) register_handler(Relation, RelationHandler.new) @@ -100,6 +99,13 @@ module ActiveRecord end private_class_method :handler_for + def self.deprecate_class_handler + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Passing a class as a value in an Active Record query is deprecated and + will be removed. Pass a string instead. + MSG + end + protected attr_reader :klass, :table diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb index b8f3285c3e..4cba297be5 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb @@ -7,16 +7,6 @@ module ActiveRecord values = value.map { |x| x.is_a?(Base) ? x.id : x } nils, values = values.partition(&:nil?) - if values.any? { |val| val.is_a?(Array) } - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Passing a nested array to Active Record finder methods is - deprecated and will be removed. Flatten your array before using - it for 'IN' conditions. - MSG - - values = values.flatten - end - return attribute.in([]) if values.empty? && nils.empty? ranges, values = values.partition { |v| v.is_a?(Range) } diff --git a/activerecord/test/cases/adapters/postgresql/network_test.rb b/activerecord/test/cases/adapters/postgresql/network_test.rb index 73e0fb5acd..4e49ea1e02 100644 --- a/activerecord/test/cases/adapters/postgresql/network_test.rb +++ b/activerecord/test/cases/adapters/postgresql/network_test.rb @@ -8,7 +8,7 @@ class PostgresqlNetworkTest < ActiveRecord::TestCase setup do @connection = ActiveRecord::Base.connection - @connection.create_table('postgresql_network_addresses') do |t| + @connection.create_table('postgresql_network_addresses', force: true) do |t| t.inet 'inet_address', default: "192.168.1.1" t.cidr 'cidr_address', default: "192.168.1.0/24" t.macaddr 'mac_address', default: "ff:ff:ff:ff:ff:ff" diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb index d90e9ccc66..70aa898439 100644 --- a/activerecord/test/cases/adapters/postgresql/numbers_test.rb +++ b/activerecord/test/cases/adapters/postgresql/numbers_test.rb @@ -5,7 +5,7 @@ class PostgresqlNumberTest < ActiveRecord::TestCase setup do @connection = ActiveRecord::Base.connection - @connection.create_table('postgresql_numbers') do |t| + @connection.create_table('postgresql_numbers', force: true) do |t| t.column 'single', 'REAL' t.column 'double', 'DOUBLE PRECISION' end diff --git a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb index 23817198b1..c88259d274 100644 --- a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb +++ b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb @@ -12,4 +12,22 @@ class PostgresqlTypeLookupTest < ActiveRecord::TestCase assert_equal ';', box_array.delimiter assert_equal ',', int_array.delimiter end + + test "array types correctly respect registration of subtypes" do + int_array = @connection.type_map.lookup(1007, -1, "integer[]") + bigint_array = @connection.type_map.lookup(1016, -1, "bigint[]") + big_array = [123456789123456789] + + assert_raises(RangeError) { int_array.type_cast_from_user(big_array) } + assert_equal big_array, bigint_array.type_cast_from_user(big_array) + end + + test "range types correctly respect registration of subtypes" do + int_range = @connection.type_map.lookup(3904, -1, "int4range") + bigint_range = @connection.type_map.lookup(3926, -1, "int8range") + big_range = 0..123456789123456789 + + assert_raises(RangeError) { int_range.type_cast_for_database(big_range) } + assert_equal "[0,123456789123456789]", bigint_range.type_cast_for_database(big_range) + end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 67bb405629..6acd9aa39f 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1527,4 +1527,14 @@ class BasicsTest < ActiveRecord::TestCase test "records without an id have unique hashes" do assert_not_equal Post.new.hash, Post.new.hash end + + test "resetting column information doesn't remove attribute methods" do + topic = topics(:first) + + assert_not topic.id_changed? + + Topic.reset_column_information + + assert_not topic.id_changed? + end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index f24b30c685..5c98be342f 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -53,10 +53,13 @@ class FinderTest < ActiveRecord::TestCase end def test_symbols_table_ref + gc_disabled = GC.disable if RUBY_VERSION >= '2.2.0' Post.where("author_id" => nil) # warm up x = Symbol.all_symbols.count Post.where("title" => {"xxxqqqq" => "bar"}) assert_equal x, Symbol.all_symbols.count + ensure + GC.enable if gc_disabled == false end # find should handle strings that come from URLs @@ -543,30 +546,6 @@ class FinderTest < ActiveRecord::TestCase assert_equal [1,2,6,7,8], Comment.where(id: [1..2, 6..8]).to_a.map(&:id).sort end - def test_find_on_hash_conditions_with_nested_array_of_integers_and_ranges - assert_deprecated do - assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [[1..2], 3, [5], 6..8, 9]).to_a.map(&:id).sort - end - end - - def test_find_on_hash_conditions_with_array_of_integers_and_arrays - assert_deprecated do - assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [[1, 2], 3, 5, [6, [7], 8], 9]).to_a.map(&:id).sort - end - end - - def test_find_on_hash_conditions_with_nested_array_of_integers_and_ranges_and_nils - assert_deprecated do - assert_equal [1,3,4,5], Topic.where(parent_id: [[2..6], nil]).to_a.map(&:id).sort - end - end - - def test_find_on_hash_conditions_with_nested_array_of_integers_and_ranges_and_more_nils - assert_deprecated do - assert_equal [], Topic.where(parent_id: [[7..10, nil, [nil]], [nil]]).to_a.map(&:id).sort - end - end - def test_find_on_multiple_hash_conditions assert Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: false).find(1) assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) } diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb index a453203e15..d675953da6 100644 --- a/activerecord/test/cases/relation/where_test.rb +++ b/activerecord/test/cases/relation/where_test.rb @@ -181,12 +181,6 @@ module ActiveRecord assert_equal 0, Post.where(:id => []).count end - def test_where_with_table_name_and_nested_empty_array - assert_deprecated do - assert_equal [], Post.where(:id => [[]]).to_a - end - end - def test_where_with_empty_hash_and_no_foreign_key assert_equal 0, Edge.where(:sink => {}).count end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index fc9637a167..3a0398d08d 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -712,7 +712,9 @@ class RelationTest < ActiveRecord::TestCase def test_find_by_classname Author.create!(:name => Mary.name) - assert_equal 1, Author.where(:name => Mary).size + assert_deprecated do + assert_equal 1, Author.where(:name => Mary).size + end end def test_find_by_id_with_list_of_ar diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 72bdd0c509..912b0287af 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,9 +1,9 @@ * Added `#verified` and `#valid_message?` methods to `ActiveSupport::MessageVerifier` - - Previously, the only way to decode a message with `ActiveSupport::MessageVerifier` was to use `#verify`, which would raise an exception on invalid messages. Now, `#verified` will return either `false` when it encounters an error or the message. - + + Previously, the only way to decode a message with `ActiveSupport::MessageVerifier` was to use `#verify`, which would raise an exception on invalid messages. Now `#verified` can also be used, which returns `nil` on messages that cannot be decoded. + Previously, there was no way to check if a message's format was valid without attempting to decode it. `#valid_message?` is a boolean convenience method that checks whether the message is valid without actually decoding it. - + *Logan Leger* Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/activesupport/CHANGELOG.md) for previous changes. diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index 2c86190e7f..d16c1c629b 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -34,7 +34,15 @@ module ActiveSupport @serializer = options[:serializer] || Marshal end - # FIXME: Document this method + # Checks if a signed message could have been generated by signing an object + # with the +MessageVerifier+'s secret. + # + # verifier = ActiveSupport::MessageVerifier.new 's3Krit' + # signed_message = verifier.generate 'a private message' + # verifier.valid_message?(signed_message) # => true + # + # tampered_message = signed_message.chop # editing the message invalidates the signature + # verifier.valid_message?(tampered_message) # => false def valid_message?(signed_message) return if signed_message.blank? @@ -42,7 +50,27 @@ module ActiveSupport data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data)) end - # FIXME: Document this method + # Decodes the signed message using the +MessageVerifier+'s secret. + # + # verifier = ActiveSupport::MessageVerifier.new 's3Krit' + # + # signed_message = verifier.generate 'a private message' + # verifier.verified(signed_message) # => 'a private message' + # + # Returns +nil+ if the message was not signed with the same secret. + # + # other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit' + # other_verifier.verified(signed_message) # => nil + # + # Returns +nil+ if the message is not Base64-encoded. + # + # invalid_message = "f--46a0120593880c733a53b6dad75b42ddc1c8996d" + # verifier.verified(invalid_message) # => nil + # + # Raises any error raised while decoding the signed message. + # + # incompatible_message = "test--dad7b06c94abba8d46a15fafaef56c327665d5ff" + # verifier.verified(incompatible_message) # => TypeError: incompatible marshal file format def verified(signed_message) if valid_message?(signed_message) begin @@ -55,12 +83,29 @@ module ActiveSupport end end - # FIXME: Document this method + # Decodes the signed message using the +MessageVerifier+'s secret. + # + # verifier = ActiveSupport::MessageVerifier.new 's3Krit' + # signed_message = verifier.generate 'a private message' + # + # verifier.verify(signed_message) # => 'a private message' + # + # Raises +InvalidSignature+ if the message was not signed with the same + # secret or was not Base64-encoded. + # + # other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit' + # other_verifier.verified(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature def verify(signed_message) verified(signed_message) || raise(InvalidSignature) end - # FIXME: Document this method + # Generates a signed message for the provided value. + # + # The message is signed with the +MessageVerifier+'s secret. Without knowing + # the secret, the original value cannot be extracted from the message. + # + # verifier = ActiveSupport::MessageVerifier.new 's3Krit' + # verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772" def generate(value) data = encode(@serializer.dump(value)) "#{data}--#{generate_digest(data)}" diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index dbee145196..9703fb6d28 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -121,16 +121,25 @@ module ActiveSupport utc? && alternate_utc_string || TimeZone.seconds_to_utc_offset(utc_offset, colon) end - # Time uses +zone+ to display the time zone abbreviation, so we're - # duck-typing it. + # Returns the time zone abbreviation. + # + # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)" + # Time.zone.now.zone # => "EST" def zone period.zone_identifier.to_s end + # Returns a string of the object's date, time, zone and offset from UTC. + # + # Time.zone.now.httpdate # => "Thu, 04 Dec 2014 11:00:25 EST -05:00" def inspect "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}" end + # Returns a string of the object's date and time in the ISO 8601 standard + # format. + # + # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00" def xmlschema(fraction_digits = 0) fraction = if fraction_digits.to_i > 0 (".%06i" % time.usec)[0, fraction_digits.to_i + 1] @@ -303,15 +312,27 @@ module ActiveSupport [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone] end + # Returns the object's date and time as a floating point number of seconds + # since the Epoch (January 1, 1970 00:00 UTC). + # + # Time.zone.now.to_f # => 1417709320.285418 def to_f utc.to_f end + # Returns the object's date and time as an integer number of seconds + # since the Epoch (January 1, 1970 00:00 UTC). + # + # Time.zone.now.to_i # => 1417709320 def to_i utc.to_i end alias_method :tv_sec, :to_i + # Returns the object's date and time as a rational number of seconds + # since the Epoch (January 1, 1970 00:00 UTC). + # + # Time.zone.now.to_r # => (708854548642709/500000) def to_r utc.to_r end diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index b6c0a08b05..eb71369397 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -1,12 +1,5 @@ require 'abstract_unit' - -begin - require 'openssl' - OpenSSL::Digest::SHA1 -rescue LoadError, NameError - $stderr.puts "Skipping MessageEncryptor test: broken OpenSSL install" -else - +require 'openssl' require 'active_support/time' require 'active_support/json' @@ -97,5 +90,3 @@ class MessageEncryptorTest < ActiveSupport::TestCase ::Base64.strict_encode64(bits) end end - -end diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index 68f40fbb28..6c3519df9a 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -1,12 +1,5 @@ require 'abstract_unit' - -begin - require 'openssl' - OpenSSL::Digest::SHA1 -rescue LoadError, NameError - $stderr.puts "Skipping MessageVerifier test: broken OpenSSL install" -else - +require 'openssl' require 'active_support/time' require 'active_support/json' @@ -41,11 +34,11 @@ class MessageVerifierTest < ActiveSupport::TestCase assert_equal @data, @verifier.verified(message) assert_equal @data, @verifier.verify(message) end - + def test_verified_returns_false_on_invalid_message assert !@verifier.verified("purejunk") end - + def test_verify_exception_on_invalid_message assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do @verifier.verify("purejunk") @@ -90,5 +83,3 @@ class MessageVerifierTest < ActiveSupport::TestCase assert_equal exception.message, 'Secret should not be nil.' end end - -end diff --git a/guides/Rakefile b/guides/Rakefile index 824bea0b39..fd093b94c1 100644 --- a/guides/Rakefile +++ b/guides/Rakefile @@ -40,7 +40,7 @@ part of the generation process. You can generate HTML, Kindle or both formats using the `guides:generate` task. -All this process is handled via rake tasks, here's a full list of them: +All of these processes are handled via rake tasks, here's a full list of them: #{%x[rake -T]} Some arguments may be passed via environment variables: diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 4eb360cc7a..17afd07820 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -24,7 +24,7 @@ NOTE: Bugs in the most recent released version of Ruby on Rails are likely to ge ### Creating a Bug Report -If you've found a problem in Ruby on Rails which is not a security risk, do a search in GitHub under [Issues](https://github.com/rails/rails/issues) in case it has already been reported. If you do not find any issue addressing it you may proceed to [open a new one](https://github.com/rails/rails/issues/new). (See the next section for reporting security issues.) +If you've found a problem in Ruby on Rails which is not a security risk, do a search in GitHub under [Issues](https://github.com/rails/rails/issues) in case it has already been reported. If you are unable to find any open GitHub issues addressing the problem you found, your next step will be to [open a new one](https://github.com/rails/rails/issues/new). (See the next section for reporting security issues.) Your issue report should contain a title and a clear description of the issue at the bare minimum. You should include as much relevant information as possible and should at least post a code sample that demonstrates the issue. It would be even better if you could include a unit test that shows how the expected behavior is not occurring. Your goal should be to make it easy for yourself - and others - to replicate the bug and figure out a fix. @@ -205,7 +205,7 @@ Rails follows a simple set of coding style conventions: * Use Ruby >= 1.9 syntax for hashes. Prefer `{ a: :b }` over `{ :a => :b }`. * Prefer `&&`/`||` over `and`/`or`. * Prefer class << self over self.method for class methods. -* Use `MyClass.my_method(my_arg)` not `my_method( my_arg )` or `my_method my_arg`. +* Use `my_method(my_arg)` not `my_method( my_arg )` or `my_method my_arg`. * Use `a = b` and not `a=b`. * Use assert_not methods instead of refute. * Prefer `method { do_stuff }` instead of `method{do_stuff}` for single-line blocks. diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index f5ae600bd8..3ea50607a5 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -111,6 +111,7 @@ module Rails jbuilder_gemfile_entry, sdoc_gemfile_entry, psych_gemfile_entry, + console_gemfile_entry, @extra_entries].flatten.find_all(&@gem_filter) end @@ -261,6 +262,15 @@ module Rails GemfileEntry.new('sdoc', '~> 0.4.0', comment, group: :doc) end + def console_gemfile_entry + comment = 'Use Rails Console on the Browser' + if options.dev? || options.edge? + GemfileEntry.github 'web-console', 'rails/web-console', comment + else + [] + end + end + def coffee_gemfile_entry comment = 'Use CoffeeScript for .coffee assets and views' if options.dev? || options.edge? diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index f9b3658ae7..7d27321610 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -9,9 +9,11 @@ module Erb # :nodoc: view_base_path = File.join("app/views", class_path, file_name) empty_directory view_base_path - formats.each do |format| - layout_path = File.join("app/views/layouts", filename_with_extensions("mailer", format)) - template filename_with_extensions(:layout, format), layout_path + if self.behavior == :invoke + formats.each do |format| + layout_path = File.join("app/views/layouts", filename_with_extensions("mailer", format)) + template filename_with_extensions(:layout, format), layout_path + end end actions.each do |action| diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index bab15ce172..3d1cf87dae 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -152,4 +152,19 @@ class MailerGeneratorTest < Rails::Generators::TestCase end end end + + def test_mailer_on_revoke + run_generator + run_generator ["notifier"], behavior: :revoke + + assert_no_file "app/mailers/notifier.rb" + assert_no_file "app/views/notifier/foo.text.erb" + assert_no_file "app/views/notifier/bar.text.erb" + assert_no_file "app/views/notifier/foo.html.erb" + assert_no_file "app/views/notifier/bar.html.erb" + + assert_file "app/mailers/application_mailer.rb" + assert_file "app/views/layouts/mailer.text.erb" + assert_file "app/views/layouts/mailer.html.erb" + end end |