diff options
33 files changed, 179 insertions, 79 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml index 877c67873d..17fcaa4360 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -7,20 +7,6 @@ ratings: - "**.rb" exclude_paths: - - actioncable/lib/rails/generators/ - - actioncable/test/ - - actionmailer/lib/rails/generators/ - - actionmailer/test/ - - actionpack/test/ - - actionview/test/ - - activejob/lib/rails/generators/ - - activejob/test/ - - activemodel/test/ - - activerecord/lib/rails/generators/ - - activerecord/test/ - - activesupport/test/ - - railties/lib/rails/generators/ - - railties/test/ - ci/ - guides/ - tasks/ @@ -27,6 +27,9 @@ gem 'uglifier', '>= 1.3.0', require: false # Track stable branch of sass because it doesn't have circular require warnings. gem 'sass', github: 'sass/sass', branch: 'stable', require: false +# FIXME: Remove this fork after https://github.com/nex3/rb-inotify/pull/49 is fixed. +gem 'rb-inotify', github: 'matthewd/rb-inotify', branch: 'close-handling', require: false + group :doc do gem 'sdoc', '~> 0.4.0' gem 'redcarpet', '~> 3.2.3', platforms: :ruby diff --git a/Gemfile.lock b/Gemfile.lock index 10bc8b1898..cf8bb0fec9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -22,6 +22,14 @@ GIT delayed_job (>= 3.0, < 5) GIT + remote: git://github.com/matthewd/rb-inotify.git + revision: 90553518d1fb79aedc98a3036c59bd2b6731ac40 + branch: close-handling + specs: + rb-inotify (0.9.7) + ffi (>= 0.5.0) + +GIT remote: git://github.com/resque/resque.git revision: 06036388ec61e573c761ac5a25a2ef3c76537ec7 specs: @@ -103,7 +111,7 @@ GEM specs: addressable (2.4.0) amq-protocol (2.0.1) - arel (7.1.0) + arel (7.1.1) backburner (1.3.0) beaneater (~> 1.0) dante (> 0.1.5) @@ -254,8 +262,6 @@ GEM loofah (~> 2.0) rake (11.1.2) rb-fsevent (0.9.7) - rb-inotify (0.9.7) - ffi (>= 0.5.0) rdoc (4.2.2) json (~> 1.4) redcarpet (3.2.3) @@ -381,6 +387,7 @@ DEPENDENCIES rack-cache (~> 1.2) rails! rake (>= 11.1) + rb-inotify! redcarpet (~> 3.2.3) redis resque! @@ -401,4 +408,4 @@ DEPENDENCIES wdm (>= 0.1.0) BUNDLED WITH - 1.11.2 + 1.12.5 diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index d50cbaee38..7bb9b62468 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,10 @@ +* Fix 'defaults' option for root route. + + A regression from some refactoring for the 5.0 release, this change + fixes the use of 'defaults' (default parameters) in the 'root' routing method. + + *Chris Arcand* + * Check `request.path_parameters` encoding at the point they're set. Check for any non-UTF8 characters in path parameters at the point they're diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 73b4864e45..12ddd0f148 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1923,7 +1923,14 @@ to this: def match_root_route(options) name = has_named_route?(:root) ? nil : :root - match '/', { :as => name, :via => :get }.merge!(options) + defaults_option = options.delete(:defaults) + args = ['/', { as: name, via: :get }.merge!(options)] + + if defaults_option + defaults(defaults_option) { match(*args) } + else + match(*args) + end end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 5298e63fef..cac89417a5 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -1759,6 +1759,24 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal 1, @request.params[:page] end + def test_keyed_default_string_params_with_root + draw do + root to: 'pages#show', defaults: { id: 'home' } + end + + get '/' + assert_equal 'home', @request.params[:id] + end + + def test_default_string_params_with_root + draw do + root to: 'pages#show', id: 'home' + end + + get '/' + assert_equal 'home', @request.params[:id] + end + def test_resource_constraints draw do resources :products, :constraints => { :id => /\d{4}/ } do diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb index f7f882c998..f0606b3834 100644 --- a/activejob/lib/active_job/core.rb +++ b/activejob/lib/active_job/core.rb @@ -105,6 +105,7 @@ module ActiveJob # end def deserialize(job_data) self.job_id = job_data['job_id'] + self.provider_job_id = job_data['provider_job_id'] self.queue_name = job_data['queue_name'] self.priority = job_data['priority'] self.serialized_arguments = job_data['arguments'] diff --git a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb index c321776bf5..3d33b3923b 100644 --- a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb @@ -37,7 +37,7 @@ module ActiveJob include Sidekiq::Worker def perform(job_data) - Base.execute job_data + Base.execute job_data.merge('provider_job_id' => jid) end end end diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb index 40f27500a5..ab3de3a8b9 100644 --- a/activejob/test/integration/queuing_test.rb +++ b/activejob/test/integration/queuing_test.rb @@ -1,6 +1,7 @@ require 'helper' require 'jobs/logging_job' require 'jobs/hello_job' +require 'jobs/provider_jid_job' require 'active_support/core_ext/numeric/time' class QueuingTest < ActiveSupport::TestCase @@ -34,6 +35,14 @@ class QueuingTest < ActiveSupport::TestCase end end + test 'should access provider_job_id inside Sidekiq job' do + skip unless adapter_is?(:sidekiq) + Sidekiq::Testing.inline! do + job = ::ProviderJidJob.perform_later + assert_equal "Provider Job ID: #{job.provider_job_id}", JobBuffer.last_value + end + end + test 'should not run job enqueued in the future' do begin TestJob.set(wait: 10.minutes).perform_later @id diff --git a/activejob/test/jobs/provider_jid_job.rb b/activejob/test/jobs/provider_jid_job.rb new file mode 100644 index 0000000000..e4f585fa94 --- /dev/null +++ b/activejob/test/jobs/provider_jid_job.rb @@ -0,0 +1,7 @@ +require_relative '../support/job_buffer' + +class ProviderJidJob < ActiveJob::Base + def perform + JobBuffer.add("Provider Job ID: #{provider_job_id}") + end +end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index d3e1cf68a2..14a6c3c9f7 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Fix the SELECT statement in `#table_comment` for MySQL. + + *Takeshi Akima* + * Virtual attributes will no longer raise when read on models loaded from the database diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index db3037d8f9..806a905323 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -29,7 +29,7 @@ module ActiveRecord # instantiation of the actual post records. class CollectionProxy < Relation delegate(*(ActiveRecord::Calculations.public_instance_methods - [:count]), to: :scope) - delegate :find_nth, :exists?, :update_all, :arel, to: :scope + delegate :exists?, :update_all, :arel, to: :scope def initialize(klass, association) #:nodoc: @association = association @@ -1070,6 +1070,12 @@ module ActiveRecord proxy_association.reset_scope self end + + private + + def exec_queries + load_target + end end end end diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index c5fbe0d1d1..bdf77009eb 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -56,7 +56,9 @@ module ActiveRecord klass_scope = if klass.current_scope - klass.current_scope.clone + klass.current_scope.clone.tap { |scope| + scope.joins_values = [] + } else relation = ActiveRecord::Relation.create( klass, diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 74aae3a1e4..e667e16964 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -18,11 +18,12 @@ module ActiveRecord # This is used in the StatementCache object. It returns an object that # can be used to query the database repeatedly. - def cacheable_query(arel) # :nodoc: + def cacheable_query(klass, arel) # :nodoc: + collected = visitor.accept(arel.ast, collector) if prepared_statements - ActiveRecord::StatementCache.query visitor, arel.ast + klass.query(collected.value) else - ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector + klass.partial_query(collected.value) end end @@ -315,7 +316,7 @@ module ActiveRecord end end key_list = fixture.keys.map { |name| quote_column_name(name) } - value_list = prepare_binds_for_database(binds).map do |value| + value_list = binds.map(&:value_for_database).map do |value| begin quote(value) rescue TypeError diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 0a58921549..eda6af08e3 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -150,10 +150,6 @@ module ActiveRecord quoted_date(value).sub(/\A2000-01-01 /, '') end - def prepare_binds_for_database(binds) # :nodoc: - binds.map(&:value_for_database) - end - private def type_casted_binds(binds) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 4f8490fa2b..0b8bacff4e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -130,7 +130,7 @@ module ActiveRecord class BindCollector < Arel::Collectors::Bind def compile(bvs, conn) - casted_binds = conn.prepare_binds_for_database(bvs) + casted_binds = bvs.map(&:value_for_database) super(casted_binds.map { |value| conn.quote(value) }) end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 25e3939b62..610d78245f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -410,10 +410,13 @@ module ActiveRecord end def table_comment(table_name) # :nodoc: + schema, name = extract_schema_qualified_name(table_name) + select_value(<<-SQL.strip_heredoc, 'SCHEMA') SELECT table_comment FROM information_schema.tables - WHERE table_name=#{quote(table_name)} + WHERE table_schema = #{quote(schema)} + AND table_name = #{quote(name)} SQL end @@ -544,7 +547,9 @@ module ActiveRecord end end - def table_options(table_name) + def table_options(table_name) # :nodoc: + table_options = {} + create_table_info = create_table_info(table_name) # strip create_definitions and partition_options @@ -553,10 +558,14 @@ module ActiveRecord # strip AUTO_INCREMENT raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1') + table_options[:options] = raw_table_options + # strip COMMENT - raw_table_options.sub!(/ COMMENT='.+'/, '') + if raw_table_options.sub!(/ COMMENT='.+'/, '') + table_options[:comment] = table_comment(table_name) + end - raw_table_options + table_options end # Maps logical Rails types to MySQL-specific data types. diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb index 5b59e39d9f..af1db30047 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb @@ -5,11 +5,11 @@ module ActiveRecord QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze def quote_column_name(name) - @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`" + @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze end def quote_table_name(name) - @quoted_table_names[name] ||= super.gsub('.', '`.`') + @quoted_table_names[name] ||= super.gsub('.', '`.`').freeze end def quoted_true diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 80c219dfd7..9fcf8dbb95 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -28,7 +28,7 @@ module ActiveRecord # - "schema.name".table_name # - "schema.name"."table.name" def quote_table_name(name) # :nodoc: - @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted + @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze end # Quotes schema names for use in SQL queries. @@ -42,7 +42,7 @@ module ActiveRecord # Quotes column names for use in SQL queries. def quote_column_name(name) # :nodoc: - @quoted_column_names[name] ||= PGconn.quote_ident(super) + @quoted_column_names[name] ||= PGconn.quote_ident(super).freeze end # Quote date/time values for use in SQL input. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index cc606e4828..4cf6d4b14a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -238,6 +238,10 @@ module ActiveRecord PostgreSQLColumn.new(*args) end + def table_options(table_name) # :nodoc: + { comment: table_comment(table_name) } + end + # Returns a comment stored in database for given table def table_comment(table_name) # :nodoc: name = Utils.extract_schema_qualified_name(table_name.to_s) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb index d5a181d3e2..fa20175b0e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb @@ -11,7 +11,7 @@ module ActiveRecord end def quote_column_name(name) - @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}") + @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}").freeze end def quoted_time(value) diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index d255cad91b..916dca33bd 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -514,7 +514,7 @@ module ActiveRecord def find_take if loaded? - @records.first + records.first else @take ||= limit(1).records.first end @@ -531,7 +531,7 @@ module ActiveRecord MSG end if loaded? - @records[index] + records[index] else offset ||= offset_index @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first @@ -557,7 +557,7 @@ module ActiveRecord def find_nth_from_last(index) if loaded? - @records[-index] + records[-index] else relation = if order_values.empty? && primary_key order(arel_attribute(primary_key).asc) @@ -578,7 +578,7 @@ module ActiveRecord def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc: if loaded? - @records[index, limit] + records[index, limit] else index += offset find_nth_with_limit(index, limit) diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index e8c176d603..cc3bb1cd06 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -127,10 +127,10 @@ HEADER tbl.print ", force: :cascade" table_options = @connection.table_options(table) - tbl.print ", options: #{table_options.inspect}" unless table_options.blank? - - if comment = @connection.table_comment(table).presence - tbl.print ", comment: #{comment.inspect}" + if table_options.present? + table_options.each do |key, value| + tbl.print ", #{key}: #{value.inspect}" if value.present? + end end tbl.puts " do |t|" diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb index 6c896ccea6..8a29547bda 100644 --- a/activerecord/lib/active_record/statement_cache.rb +++ b/activerecord/lib/active_record/statement_cache.rb @@ -40,7 +40,7 @@ module ActiveRecord end class PartialQuery < Query # :nodoc: - def initialize values + def initialize(values) @values = values @indexes = values.each_with_index.find_all { |thing,i| Arel::Nodes::BindParam === thing @@ -49,19 +49,18 @@ module ActiveRecord def sql_for(binds, connection) val = @values.dup - binds = connection.prepare_binds_for_database(binds) - @indexes.each { |i| val[i] = connection.quote(binds.shift) } + casted_binds = binds.map(&:value_for_database) + @indexes.each { |i| val[i] = connection.quote(casted_binds.shift) } val.join end end - def self.query(visitor, ast) - Query.new visitor.accept(ast, Arel::Collectors::SQLString.new).value + def self.query(sql) + Query.new(sql) end - def self.partial_query(visitor, ast, collector) - collected = visitor.accept(ast, collector).value - PartialQuery.new collected + def self.partial_query(values) + PartialQuery.new(values) end class Params # :nodoc: @@ -92,7 +91,7 @@ module ActiveRecord def self.create(connection, block = Proc.new) relation = block.call Params.new bind_map = BindMap.new relation.bound_attributes - query_builder = connection.cacheable_query relation.arel + query_builder = connection.cacheable_query(self, relation.arel) new query_builder, bind_map end diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb index a1326aa359..5fe0d8b5e4 100644 --- a/activerecord/lib/active_record/table_metadata.rb +++ b/activerecord/lib/active_record/table_metadata.rb @@ -42,11 +42,11 @@ module ActiveRecord end def associated_table(table_name) - return self if table_name == arel_table.name - association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.singularize) - if association && !association.polymorphic? + if !association && table_name == arel_table.name + return self + elsif association && !association.polymorphic? association_klass = association.klass arel_table = association_klass.arel_table.alias(table_name) else 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 e27f16b6e4..a959f3c06a 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 @@ -19,6 +19,7 @@ require 'models/professor' require 'models/treasure' require 'models/price_estimate' require 'models/club' +require 'models/user' require 'models/member' require 'models/membership' require 'models/sponsor' @@ -995,4 +996,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase Project.first.developers_required_by_default.create!(name: "Sean", salary: 50000) end end + + def test_association_name_is_the_same_as_join_table_name + user = User.create! + assert_nothing_raised { user.jobs_pool.clear } + end end diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 5fb7f191ed..7efacb44f3 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -181,6 +181,14 @@ class AssociationProxyTest < ActiveRecord::TestCase assert !david.projects.loaded? end + def test_load_does_load_target + david = developers(:david) + + assert !david.projects.loaded? + david.projects.load + assert david.projects.loaded? + end + def test_inspect_does_not_reload_a_not_yet_loaded_target andreas = Developer.new :name => 'Andreas', :log => 'new developer added' assert !andreas.audit_logs.loaded? @@ -246,6 +254,8 @@ class AssociationProxyTest < ActiveRecord::TestCase test "first! works on loaded associations" do david = authors(:david) assert_equal david.posts.first, david.posts.reload.first! + assert david.posts.loaded? + assert_no_queries { david.posts.first! } end def test_reset_unloads_target diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb index c15d57460b..ef46fd5d9a 100644 --- a/activerecord/test/cases/scoping/relation_scoping_test.rb +++ b/activerecord/test/cases/scoping/relation_scoping_test.rb @@ -228,6 +228,13 @@ class RelationScopingTest < ActiveRecord::TestCase assert SpecialComment.all.any? end end + + def test_circular_joins_with_current_scope_does_not_crash + posts = Post.joins(comments: :post).scoping do + Post.current_scope.first(10) + end + assert_equal posts, Post.joins(comments: :post).first(10) + end end class NestedRelationScopingTest < ActiveRecord::TestCase diff --git a/activerecord/test/models/user.rb b/activerecord/test/models/user.rb index f5dc93e994..97107a35a0 100644 --- a/activerecord/test/models/user.rb +++ b/activerecord/test/models/user.rb @@ -1,6 +1,12 @@ +require 'models/job' + class User < ActiveRecord::Base has_secure_token has_secure_token :auth_token + + has_and_belongs_to_many :jobs_pool, + class_name: Job, + join_table: 'jobs_pool' end class UserWithNotification < User diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 2f2993ce18..a5155e9cdb 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -390,6 +390,11 @@ ActiveRecord::Schema.define do t.integer :ideal_reference_id end + create_table :jobs_pool, force: true, id: false do |t| + t.references :job, null: false, index: true + t.references :user, null: false, index: true + end + create_table :keyboards, force: true, id: false do |t| t.primary_key :key_number t.string :name diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb index 87efe117c5..1f2736388d 100644 --- a/activesupport/lib/active_support/message_encryptor.rb +++ b/activesupport/lib/active_support/message_encryptor.rb @@ -99,6 +99,10 @@ module ActiveSupport def _decrypt(encrypted_message) cipher = new_cipher encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map {|v| ::Base64.strict_decode64(v)} + + # Currently the OpenSSL bindings do not raise an error if auth_tag is + # truncated, which would allow an attacker to easily forge it. See + # https://github.com/ruby/openssl/issues/63 raise InvalidMessage if aead_mode? && auth_tag.bytes.length != 16 cipher.decrypt diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 90f200133b..8ffd0d033d 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -601,6 +601,7 @@ If you want to call `order` multiple times, subsequent orders will be appended t Client.order("orders_count ASC").order("created_at DESC") # SELECT * FROM clients ORDER BY orders_count ASC, created_at DESC ``` +WARNING: If you are using **MySQL 5.7.5** and above, then on selecting fields from a result set using methods like `select`, `pluck` and `ids`; the `order` method will raise an `ActiveRecord::StatementInvalid` exception unless the field(s) used in `order` clause are included in the select list. See the next section for selecting fields from the result set. Selecting Specific Fields ------------------------- diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 0f1c3735e8..73dbb2bc40 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -465,29 +465,24 @@ The first part identifies which template is missing. In this case, it's the then it will attempt to load a template called `application/new`. It looks for one here because the `ArticlesController` inherits from `ApplicationController`. -The next part of the message contains a hash. The `:locale` key in this hash -simply indicates which spoken language template should be retrieved. By default, -this is the English - or "en" - template. The next key, `:formats` specifies the -format of the template to be served in response. The default format is `:html`, and -so Rails is looking for an HTML template. The final key, `:handlers`, is telling -us what _template handlers_ could be used to render our template. `:erb` is most -commonly used for HTML templates, `:builder` is used for XML templates, and -`:coffee` uses CoffeeScript to build JavaScript templates. - -The message also contains `request.formats` which specifies the format of template to be -served in response. It is set to `text/html` as we requested this page via browser, so Rails -is looking for an HTML template. +The next part of the message contains `request.formats` which specifies +the format of template to be served in response. It is set to `text/html` as we +requested this page via browser, so Rails is looking for an HTML template. +`request.variants` specifies what kind of physical devices would be served by +the response and helps Rails determine which template to use in the response. +It is empty because no information has been provided. The simplest template that would work in this case would be one located at `app/views/articles/new.html.erb`. The extension of this file name is important: the first extension is the _format_ of the template, and the second extension -is the _handler_ that will be used. Rails is attempting to find a template -called `articles/new` within `app/views` for the application. The format for -this template can only be `html` and the handler must be one of `erb`, -`builder` or `coffee`. `:erb` is most commonly used for HTML templates, `:builder` is -used for XML templates, and `:coffee` uses CoffeeScript to build JavaScript templates. -Because you want to create a new HTML form, you will be -using the `ERB` language which is designed to embed Ruby in HTML. +is the _handler_ that will be used to render the template. Rails is attempting +to find a template called `articles/new` within `app/views` for the +application. The format for this template can only be `html` and the default +handler for HTML is `erb`. Rails uses other handlers for other formats. +`builder` handler is used to build XML templates and `coffee` handler uses +CoffeeScript to build JavaScript templates. Because you want to create a new +HTML form, you will be using the `ERB` language which is designed to embed Ruby +in HTML. Therefore the file should be called `articles/new.html.erb` and needs to be located inside the `app/views` directory of the application. |