aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md15
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb1
-rw-r--r--actionview/lib/action_view/helpers/javascript_helper.rb2
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb18
-rw-r--r--actionview/lib/action_view/renderer/renderer.rb2
-rw-r--r--actionview/lib/action_view/renderer/template_renderer.rb2
-rw-r--r--activerecord/CHANGELOG.md11
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb93
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb56
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb30
-rw-r--r--activerecord/lib/active_record/core.rb9
-rw-r--r--activerecord/lib/active_record/railtie.rb8
-rw-r--r--activerecord/lib/active_record/relation/record_fetch_warning.rb49
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/numbers_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb16
-rw-r--r--activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb6
-rw-r--r--activerecord/test/cases/query_cache_test.rb2
-rw-r--r--activerecord/test/cases/relation/record_fetch_warning_test.rb28
-rw-r--r--activerecord/test/cases/tasks/postgresql_rake_test.rb4
-rw-r--r--activesupport/lib/active_support/callbacks.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/module/aliasing.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/deprecation.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb2
-rw-r--r--activesupport/lib/active_support/subscriber.rb9
-rw-r--r--guides/source/4_0_release_notes.md38
-rw-r--r--guides/source/4_2_release_notes.md30
-rw-r--r--guides/source/active_record_migrations.md8
-rw-r--r--guides/source/active_record_querying.md2
-rw-r--r--guides/source/active_record_validations.md8
-rw-r--r--guides/source/asset_pipeline.md3
-rw-r--r--guides/source/command_line.md2
-rw-r--r--guides/source/configuring.md5
-rw-r--r--guides/source/form_helpers.md2
-rw-r--r--guides/source/getting_started.md2
-rw-r--r--guides/source/routing.md2
-rw-r--r--guides/source/testing.md8
-rw-r--r--railties/CHANGELOG.md6
-rw-r--r--railties/lib/rails/generators/named_base.rb4
-rw-r--r--railties/lib/rails/generators/test_unit/model/model_generator.rb2
-rw-r--r--railties/test/generators/model_generator_test.rb10
45 files changed, 280 insertions, 236 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index e3e5787183..0ae96441ce 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -12,13 +12,20 @@
*George Claghorn*
+* Fix regression where a gzip file response would have a Content-type,
+ even when it was a 304 status code.
+
+ See #19271.
+
+ *Kohei Suzuki*
+
* Fix handling of empty X_FORWARDED_HOST header in raw_host_with_port
- Previously, an empty X_FORWARDED_HOST header would cause
- Actiondispatch::Http:URL.raw_host_with_port to return nil, causing
- Actiondispatch::Http:URL.host to raise a NoMethodError.
+ Previously, an empty X_FORWARDED_HOST header would cause
+ Actiondispatch::Http:URL.raw_host_with_port to return nil, causing
+ Actiondispatch::Http:URL.host to raise a NoMethodError.
- *Adam Forsyth*
+ *Adam Forsyth*
* Drop request class from RouteSet constructor.
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index f2a74ea647..891cc53765 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -141,6 +141,7 @@ module ActionView
# will get expanded to
#
# <%= text_field :person, :first_name %>
+ #
# which results in an HTML <tt><input></tt> tag whose +name+ attribute is
# <tt>person[first_name]</tt>. This means that when the form is submitted,
# the value entered by the user will be available in the controller as
diff --git a/actionview/lib/action_view/helpers/javascript_helper.rb b/actionview/lib/action_view/helpers/javascript_helper.rb
index 629c447f3f..e237a32cb7 100644
--- a/actionview/lib/action_view/helpers/javascript_helper.rb
+++ b/actionview/lib/action_view/helpers/javascript_helper.rb
@@ -21,7 +21,7 @@ module ActionView
# Also available through the alias j(). This is particularly helpful in JavaScript
# responses, like:
#
- # $('some_element').replaceWith('<%=j render 'some/element_template' %>');
+ # $('some_element').replaceWith('<%= j render 'some/element_template' %>');
def escape_javascript(javascript)
if javascript
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index 56b8ab1e2d..cd151c0189 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -154,23 +154,23 @@ module ActionView
# specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
# of users:
#
- # <%# app/views/users/index.html.erb &>
+ # <%# app/views/users/index.html.erb %>
# Here's the administrator:
# <%= render partial: "user", layout: "administrator", locals: { user: administrator } %>
#
# Here's the editor:
# <%= render partial: "user", layout: "editor", locals: { user: editor } %>
#
- # <%# app/views/users/_user.html.erb &>
+ # <%# app/views/users/_user.html.erb %>
# Name: <%= user.name %>
#
- # <%# app/views/users/_administrator.html.erb &>
+ # <%# app/views/users/_administrator.html.erb %>
# <div id="administrator">
# Budget: $<%= user.budget %>
# <%= yield %>
# </div>
#
- # <%# app/views/users/_editor.html.erb &>
+ # <%# app/views/users/_editor.html.erb %>
# <div id="editor">
# Deadline: <%= user.deadline %>
# <%= yield %>
@@ -233,7 +233,7 @@ module ActionView
#
# You can also apply a layout to a block within any template:
#
- # <%# app/views/users/_chief.html.erb &>
+ # <%# app/views/users/_chief.html.erb %>
# <%= render(layout: "administrator", locals: { user: chief }) do %>
# Title: <%= chief.title %>
# <% end %>
@@ -250,13 +250,13 @@ module ActionView
# If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
# an array to layout and treat it as an enumerable.
#
- # <%# app/views/users/_user.html.erb &>
+ # <%# app/views/users/_user.html.erb %>
# <div class="user">
# Budget: $<%= user.budget %>
# <%= yield user %>
# </div>
#
- # <%# app/views/users/index.html.erb &>
+ # <%# app/views/users/index.html.erb %>
# <%= render layout: @users do |user| %>
# Title: <%= user.title %>
# <% end %>
@@ -265,14 +265,14 @@ module ActionView
#
# You can also yield multiple times in one layout and use block arguments to differentiate the sections.
#
- # <%# app/views/users/_user.html.erb &>
+ # <%# app/views/users/_user.html.erb %>
# <div class="user">
# <%= yield user, :header %>
# Budget: $<%= user.budget %>
# <%= yield user, :footer %>
# </div>
#
- # <%# app/views/users/index.html.erb &>
+ # <%# app/views/users/index.html.erb %>
# <%= render layout: @users do |user, section| %>
# <%- case section when :header -%>
# Title: <%= user.title %>
diff --git a/actionview/lib/action_view/renderer/renderer.rb b/actionview/lib/action_view/renderer/renderer.rb
index 964b18337e..1bee35d80d 100644
--- a/actionview/lib/action_view/renderer/renderer.rb
+++ b/actionview/lib/action_view/renderer/renderer.rb
@@ -37,7 +37,7 @@ module ActionView
end
end
- # Direct accessor to template rendering.
+ # Direct access to template rendering.
def render_template(context, options) #:nodoc:
TemplateRenderer.new(@lookup_context).render(context, options)
end
diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
index cd21d7ab47..dbb4855e39 100644
--- a/actionview/lib/action_view/renderer/template_renderer.rb
+++ b/actionview/lib/action_view/renderer/template_renderer.rb
@@ -40,7 +40,7 @@ module ActionView
find_template(options[:template], options[:prefixes], false, keys, @details)
end
else
- raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :text or :body option."
+ raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html, :text or :body option."
end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index accf356a0c..be3a461eda 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Add `config.active_record.warn_on_records_fetched_greater_than` option
+
+ When set to an integer, a warning will be logged whenever a result set
+ larger than the specified size is returned by a query. Fixes #16463
+
+ *Jason Nochlin*
+
+* Ignore psqlrc when loading database structure.
+
+ *Jason Weathered*
+
* Fix referencing wrong table aliases while joining tables of has many through
association (only when calling calculation methods).
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index cc03e37a12..93550a69f1 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -258,7 +258,7 @@ module ActiveRecord #:nodoc:
# <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of
# AttributeAssignmentError
# objects that should be inspected to determine which attributes triggered the errors.
- # * RecordInvalid - raised by save! and create! when the record is invalid.
+ # * RecordInvalid - raised by <tt>save!</tt> and <tt>create!</tt> when the record is invalid.
# * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
# or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
# nothing was found, please check its documentation for further details.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb b/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb
deleted file mode 100644
index 1b74c039ce..0000000000
--- a/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-module ActiveRecord
- module ConnectionAdapters
- module PostgreSQL
- module ArrayParser # :nodoc:
-
- DOUBLE_QUOTE = '"'
- BACKSLASH = "\\"
- COMMA = ','
- BRACKET_OPEN = '{'
- BRACKET_CLOSE = '}'
-
- def parse_pg_array(string) # :nodoc:
- local_index = 0
- array = []
- while(local_index < string.length)
- case string[local_index]
- when BRACKET_OPEN
- local_index,array = parse_array_contents(array, string, local_index + 1)
- when BRACKET_CLOSE
- return array
- end
- local_index += 1
- end
-
- array
- end
-
- private
-
- def parse_array_contents(array, string, index)
- is_escaping = false
- is_quoted = false
- was_quoted = false
- current_item = ''
-
- local_index = index
- while local_index
- token = string[local_index]
- if is_escaping
- current_item << token
- is_escaping = false
- else
- if is_quoted
- case token
- when DOUBLE_QUOTE
- is_quoted = false
- was_quoted = true
- when BACKSLASH
- is_escaping = true
- else
- current_item << token
- end
- else
- case token
- when BACKSLASH
- is_escaping = true
- when COMMA
- add_item_to_array(array, current_item, was_quoted)
- current_item = ''
- was_quoted = false
- when DOUBLE_QUOTE
- is_quoted = true
- when BRACKET_OPEN
- internal_items = []
- local_index,internal_items = parse_array_contents(internal_items, string, local_index + 1)
- array.push(internal_items)
- when BRACKET_CLOSE
- add_item_to_array(array, current_item, was_quoted)
- return local_index,array
- else
- current_item << token
- end
- end
- end
-
- local_index += 1
- end
- return local_index,array
- end
-
- def add_item_to_array(array, current_item, quoted)
- return if !quoted && current_item.length == 0
-
- if !quoted && current_item == 'NULL'
- array.push nil
- else
- array.push current_item
- end
- end
- end
- end
- end
-end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index f486c5ecb7..3de794f797 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -5,29 +5,20 @@ module ActiveRecord
class Array < Type::Value # :nodoc:
include Type::Helpers::Mutable
- # Loads pg_array_parser if available. String parsing can be
- # performed quicker by a native extension, which will not create
- # a large amount of Ruby objects that will need to be garbage
- # collected. pg_array_parser has a C and Java extension
- begin
- require 'pg_array_parser'
- include PgArrayParser
- rescue LoadError
- require 'active_record/connection_adapters/postgresql/array_parser'
- include PostgreSQL::ArrayParser
- end
-
attr_reader :subtype, :delimiter
delegate :type, :user_input_in_time_zone, :limit, to: :subtype
def initialize(subtype, delimiter = ',')
@subtype = subtype
@delimiter = delimiter
+
+ @pg_encoder = PG::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter
+ @pg_decoder = PG::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter
end
def deserialize(value)
if value.is_a?(::String)
- type_cast_array(parse_pg_array(value), :deserialize)
+ type_cast_array(@pg_decoder.decode(value), :deserialize)
else
super
end
@@ -35,14 +26,14 @@ module ActiveRecord
def cast(value)
if value.is_a?(::String)
- value = parse_pg_array(value)
+ value = @pg_decoder.decode(value)
end
type_cast_array(value, :cast)
end
def serialize(value)
if value.is_a?(::Array)
- cast_value_for_database(value)
+ @pg_encoder.encode(type_cast_array(value, :serialize))
else
super
end
@@ -63,41 +54,6 @@ module ActiveRecord
@subtype.public_send(method, value)
end
end
-
- def cast_value_for_database(value)
- if value.is_a?(::Array)
- casted_values = value.map { |item| cast_value_for_database(item) }
- "{#{casted_values.join(delimiter)}}"
- else
- quote_and_escape(subtype.serialize(value))
- end
- end
-
- ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
-
- def quote_and_escape(value)
- case value
- when ::String
- if string_requires_quoting?(value)
- value = value.gsub(/\\/, ARRAY_ESCAPE)
- value.gsub!(/"/,"\\\"")
- %("#{value}")
- else
- value
- end
- when nil then "NULL"
- else value
- end
- end
-
- # See http://www.postgresql.org/docs/9.2/static/arrays.html#ARRAYS-IO
- # for a list of all cases in which strings will be quoted.
- def string_requires_quoting?(string)
- string.empty? ||
- string == "NULL" ||
- string =~ /[\{\}"\\\s]/ ||
- string.include?(delimiter)
- end
end
end
end
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 9b3de41fab..9d421d6975 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
@@ -19,7 +19,7 @@ module ActiveRecord
enums, nodes = nodes.partition { |row| row['typtype'] == 'e' }
domains, nodes = nodes.partition { |row| row['typtype'] == 'd' }
arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
- composites, nodes = nodes.partition { |row| row['typelem'] != '0' }
+ composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 }
mapped.each { |row| register_mapped_type(row) }
enums.each { |row| register_enum_type(row) }
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 eeb141dd1e..cb0b9cdbe9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -129,8 +129,8 @@ module ActiveRecord
result.map do |row|
index_name = row[0]
- unique = row[1] == 't'
- indkey = row[2].split(" ")
+ unique = row[1]
+ indkey = row[2].split(" ").map(&:to_i)
inddef = row[3]
oid = row[4]
@@ -164,7 +164,7 @@ module ActiveRecord
type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
default_value = extract_value_from_default(default)
default_function = extract_default_function(default_value, default)
- new_column(column_name, default_value, type_metadata, notnull == 'f', default_function)
+ new_column(column_name, default_value, type_metadata, !notnull, default_function)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 96a3ac7c31..e616cee5eb 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -1,3 +1,7 @@
+# Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
+gem 'pg', '~> 0.18'
+require 'pg'
+
require "active_record/connection_adapters/abstract_adapter"
require "active_record/connection_adapters/postgresql/column"
require "active_record/connection_adapters/postgresql/database_statements"
@@ -12,10 +16,6 @@ require "active_record/connection_adapters/statement_pool"
require 'arel/visitors/bind_visitor'
-# Make sure we're using pg high enough for Ruby 2.2+ compatibility
-gem 'pg', '~> 0.18'
-require 'pg'
-
require 'ipaddr'
module ActiveRecord
@@ -278,8 +278,7 @@ module ActiveRecord
@table_alias_length = nil
connect
- add_pg_decoders
-
+ add_pg_encoders
@statements = StatementPool.new @connection,
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 })
@@ -287,6 +286,8 @@ module ActiveRecord
raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
end
+ add_pg_decoders
+
@type_map = Type::HashLookupTypeMap.new
initialize_type_map(type_map)
@local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
@@ -798,11 +799,20 @@ module ActiveRecord
)
end_sql
execute_and_clear(sql, "SCHEMA", []) do |result|
- result.getvalue(0, 0) == 't'
+ result.getvalue(0, 0)
end
end
end
+ def add_pg_encoders
+ map = PG::TypeMapByClass.new
+ map[Integer] = PG::TextEncoder::Integer.new
+ map[TrueClass] = PG::TextEncoder::Boolean.new
+ map[FalseClass] = PG::TextEncoder::Boolean.new
+ map[Float] = PG::TextEncoder::Float.new
+ @connection.type_map_for_queries = map
+ end
+
def add_pg_decoders
coders_by_name = {
'int2' => PG::TextDecoder::Integer,
@@ -814,12 +824,12 @@ module ActiveRecord
'bool' => PG::TextDecoder::Boolean,
}
query = <<-SQL
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
+ SELECT t.oid, t.typname
FROM pg_type as t
SQL
coders = execute_and_clear(query, "SCHEMA", []) do |result|
result
- .map { |row| construct_coder(row, coders_by_name['typname']) }
+ .map { |row| construct_coder(row, coders_by_name[row['typname']]) }
.compact
end
@@ -830,7 +840,7 @@ module ActiveRecord
def construct_coder(row, coder_class)
return unless coder_class
- coder_class.new(oid: row['oid'], name: row['typname'])
+ coder_class.new(oid: row['oid'].to_i, name: row['typname'])
end
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 9a39a0e919..09d7ac374a 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -94,6 +94,15 @@ module ActiveRecord
mattr_accessor :dump_schemas, instance_writer: false
self.dump_schemas = :schema_search_path
+ ##
+ # :singleton-method:
+ # Specify a threshold for the size of query result sets. If the number of
+ # records in the set exceeds the threshold, a warning is logged. This can
+ # be used to identify queries which load thousands of records and
+ # potentially cause memory bloat.
+ mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
+ self.warn_on_records_fetched_greater_than = nil
+
mattr_accessor :maintain_test_schema, instance_accessor: false
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index f1bdbc845c..7e907beec0 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -102,6 +102,14 @@ module ActiveRecord
end
end
+ initializer "active_record.warn_on_records_fetched_greater_than" do
+ if config.active_record.warn_on_records_fetched_greater_than
+ ActiveSupport.on_load(:active_record) do
+ require 'active_record/relation/record_fetch_warning'
+ end
+ end
+ end
+
initializer "active_record.set_configs" do |app|
ActiveSupport.on_load(:active_record) do
app.config.active_record.each do |k,v|
diff --git a/activerecord/lib/active_record/relation/record_fetch_warning.rb b/activerecord/lib/active_record/relation/record_fetch_warning.rb
new file mode 100644
index 0000000000..14e1bf89fa
--- /dev/null
+++ b/activerecord/lib/active_record/relation/record_fetch_warning.rb
@@ -0,0 +1,49 @@
+module ActiveRecord
+ class Relation
+ module RecordFetchWarning
+ # When this module is prepended to ActiveRecord::Relation and
+ # `config.active_record.warn_on_records_fetched_greater_than` is
+ # set to an integer, if the number of records a query returns is
+ # greater than the value of `warn_on_records_fetched_greater_than`,
+ # a warning is logged. This allows for the detection of queries that
+ # return a large number of records, which could cause memory bloat.
+ #
+ # In most cases, fetching large number of records can be performed
+ # efficiently using the ActiveRecord::Batches methods.
+ # See active_record/lib/relation/batches.rb for more information.
+ def exec_queries
+ QueryRegistry.reset
+
+ super.tap do
+ if logger && warn_on_records_fetched_greater_than
+ if @records.length > warn_on_records_fetched_greater_than
+ logger.warn "Query fetched #{@records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
+ end
+ end
+ end
+ end
+
+ ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
+ payload = args.last
+
+ QueryRegistry.queries << payload[:sql]
+ end
+
+ class QueryRegistry # :nodoc:
+ extend ActiveSupport::PerThreadRegistry
+
+ attr_accessor :queries
+
+ def initialize
+ reset
+ end
+
+ def reset
+ @queries = []
+ end
+ end
+ end
+ end
+end
+
+ActiveRecord::Relation.prepend ActiveRecord::Relation::RecordFetchWarning
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index 435708a421..d7da95c8a9 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -67,7 +67,7 @@ module ActiveRecord
def structure_load(filename)
set_psql_env
- Kernel.system("psql -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
+ Kernel.system("psql -X -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
end
private
diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb
index 093b81fe8d..d8e01e3b89 100644
--- a/activerecord/test/cases/adapters/postgresql/numbers_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/numbers_test.rb
@@ -31,7 +31,7 @@ class PostgresqlNumberTest < ActiveRecord::TestCase
assert_equal 123456.789, first.double
assert_equal(-::Float::INFINITY, second.single)
assert_equal ::Float::INFINITY, second.double
- assert_same ::Float::NAN, third.double
+ assert_send [third.double, :nan?]
end
def test_update
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index a934180a43..9a1b889d4d 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -68,7 +68,7 @@ module ActiveRecord
def test_insert_sql_with_proprietary_returning_clause
with_example_table do
id = @connection.insert_sql("insert into ex (number) values(5150)", nil, "number")
- assert_equal "5150", id
+ assert_equal 5150, id
end
end
@@ -106,21 +106,21 @@ module ActiveRecord
connection = connection_without_insert_returning
id = connection.insert_sql("insert into postgresql_partitioned_table_parent (number) VALUES (1)")
expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
- assert_equal expect, id
+ assert_equal expect.to_i, id
end
def test_exec_insert_with_returning_disabled
connection = connection_without_insert_returning
result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id', 'postgresql_partitioned_table_parent_id_seq')
expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
- assert_equal expect, result.rows.first.first
+ assert_equal expect.to_i, result.rows.first.first
end
def test_exec_insert_with_returning_disabled_and_no_sequence_name_given
connection = connection_without_insert_returning
result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id')
expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first
- assert_equal expect, result.rows.first.first
+ assert_equal expect.to_i, result.rows.first.first
end
def test_sql_for_insert_with_returning_disabled
@@ -238,7 +238,7 @@ module ActiveRecord
result = @connection.exec_query('SELECT number FROM ex WHERE number = 10')
assert_equal 1, result.rows.length
- assert_equal "10", result.rows.last.last
+ assert_equal 10, result.rows.last.last
end
end
@@ -274,7 +274,7 @@ module ActiveRecord
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
- assert_equal [['1', 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
end
end
@@ -288,7 +288,7 @@ module ActiveRecord
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
- assert_equal [['1', 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
end
end
@@ -304,7 +304,7 @@ module ActiveRecord
assert_equal 1, result.rows.length
assert_equal 2, result.columns.length
- assert_equal [['1', 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
index d76e762815..7200ed2771 100644
--- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb
@@ -106,6 +106,6 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::TestCase
private
def assert_transaction_is_not_broken
- assert_equal "1", @connection.select_value("SELECT 1")
+ assert_equal 1, @connection.select_value("SELECT 1")
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index c1be340e7c..f925dcad97 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -384,16 +384,16 @@ class SchemaTest < ActiveRecord::TestCase
def test_reset_pk_sequence
sequence_name = "#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}"
@connection.execute "SELECT setval('#{sequence_name}', 123)"
- assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')")
+ assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')")
@connection.reset_pk_sequence!("#{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME}")
- assert_equal "1", @connection.select_value("SELECT nextval('#{sequence_name}')")
+ assert_equal 1, @connection.select_value("SELECT nextval('#{sequence_name}')")
end
def test_set_pk_sequence
table_name = "#{SCHEMA_NAME}.#{PK_TABLE_NAME}"
_, sequence_name = @connection.pk_and_sequence_for table_name
@connection.set_pk_sequence! table_name, 123
- assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')")
+ assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')")
@connection.reset_pk_sequence! table_name
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 744f9edc47..2f0b5df286 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -184,7 +184,7 @@ class QueryCacheTest < ActiveRecord::TestCase
# Oracle adapter returns count() as Fixnum or Float
if current_adapter?(:OracleAdapter)
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
- elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter)
+ elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter)
# Future versions of the sqlite3 adapter will return numeric
assert_instance_of Fixnum,
Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
diff --git a/activerecord/test/cases/relation/record_fetch_warning_test.rb b/activerecord/test/cases/relation/record_fetch_warning_test.rb
new file mode 100644
index 0000000000..62f0a7cc49
--- /dev/null
+++ b/activerecord/test/cases/relation/record_fetch_warning_test.rb
@@ -0,0 +1,28 @@
+require 'cases/helper'
+require 'models/post'
+
+module ActiveRecord
+ class RecordFetchWarningTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def test_warn_on_records_fetched_greater_than
+ original_logger = ActiveRecord::Base.logger
+ orginal_warn_on_records_fetched_greater_than = ActiveRecord::Base.warn_on_records_fetched_greater_than
+
+ log = StringIO.new
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
+ ActiveRecord::Base.logger.level = Logger::WARN
+
+ require 'active_record/relation/record_fetch_warning'
+
+ ActiveRecord::Base.warn_on_records_fetched_greater_than = 1
+
+ Post.all.to_a
+
+ assert_match(/Query fetched/, log.string)
+ ensure
+ ActiveRecord::Base.logger = original_logger
+ ActiveRecord::Base.warn_on_records_fetched_greater_than = orginal_warn_on_records_fetched_greater_than
+ end
+ end
+end
diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb
index d45fb07417..084302cde5 100644
--- a/activerecord/test/cases/tasks/postgresql_rake_test.rb
+++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb
@@ -261,14 +261,14 @@ module ActiveRecord
def test_structure_load
filename = "awesome-file.sql"
- Kernel.expects(:system).with("psql -q -f #{filename} my-app-db")
+ Kernel.expects(:system).with("psql -X -q -f #{filename} my-app-db")
ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
end
def test_structure_load_accepts_path_with_spaces
filename = "awesome file.sql"
- Kernel.expects(:system).with("psql -q -f awesome\\ file.sql my-app-db")
+ Kernel.expects(:system).with("psql -X -q -f awesome\\ file.sql my-app-db")
ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 37f9494272..08520b1077 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -5,6 +5,7 @@ require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/kernel/singleton_class'
require 'active_support/core_ext/string/filters'
+require 'active_support/deprecation'
require 'thread'
module ActiveSupport
diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb
index 25e138264e..dcc1cd5ba9 100644
--- a/activesupport/lib/active_support/core_ext/module/aliasing.rb
+++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb
@@ -1,3 +1,5 @@
+require 'active_support/deprecation'
+
class Module
# Encapsulates the common pattern of:
#
diff --git a/activesupport/lib/active_support/core_ext/module/deprecation.rb b/activesupport/lib/active_support/core_ext/module/deprecation.rb
index 56d670fbe8..5134b5ad41 100644
--- a/activesupport/lib/active_support/core_ext/module/deprecation.rb
+++ b/activesupport/lib/active_support/core_ext/module/deprecation.rb
@@ -1,3 +1,5 @@
+require 'active_support/deprecation'
+
class Module
# deprecate :foo
# deprecate bar: 'message'
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index bae4e206e6..c676b26b06 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -13,7 +13,7 @@ class ERB
# This method is also aliased as <tt>h</tt>.
#
# In your ERB templates, use this method to escape any unsafe content. For example:
- # <%=h @person.name %>
+ # <%= h @person.name %>
#
# puts html_escape('is a > 0 & a < 10?')
# # => is a &gt; 0 &amp; a &lt; 10?
diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb
index cd40284660..8db423f0e9 100644
--- a/activesupport/lib/active_support/subscriber.rb
+++ b/activesupport/lib/active_support/subscriber.rb
@@ -10,19 +10,14 @@ module ActiveSupport
#
# module ActiveRecord
# class StatsSubscriber < ActiveSupport::Subscriber
+ # attach_to :active_record
+ #
# def sql(event)
# Statsd.timing("sql.#{event.payload[:name]}", event.duration)
# end
# end
# end
#
- # And it's finally registered as:
- #
- # ActiveRecord::StatsSubscriber.attach_to :active_record
- #
- # Since we need to know all instance methods before attaching the log
- # subscriber, the line above should be called after your subscriber definition.
- #
# After configured, whenever a "sql.active_record" notification is published,
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
# the +sql+ method.
diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md
index bbc0efa3ea..9feaff098a 100644
--- a/guides/source/4_0_release_notes.md
+++ b/guides/source/4_0_release_notes.md
@@ -59,25 +59,25 @@ Major Features
### Upgrade
- * **Ruby 1.9.3** ([commit](https://github.com/rails/rails/commit/a0380e808d3dbd2462df17f5d3b7fcd8bd812496)) - Ruby 2.0 preferred; 1.9.3+ required
- * **[New deprecation policy](http://www.youtube.com/watch?v=z6YgD6tVPQs)** - Deprecated features are warnings in Rails 4.0 and will be removed in Rails 4.1.
- * **ActionPack page and action caching** ([commit](https://github.com/rails/rails/commit/b0a7068564f0c95e7ef28fc39d0335ed17d93e90)) - Page and action caching are extracted to a separate gem. Page and action caching requires too much manual intervention (manually expiring caches when the underlying model objects are updated). Instead, use Russian doll caching.
- * **ActiveRecord observers** ([commit](https://github.com/rails/rails/commit/ccecab3ba950a288b61a516bf9b6962e384aae0b)) - Observers are extracted to a separate gem. Observers are only needed for page and action caching, and can lead to spaghetti code.
- * **ActiveRecord session store** ([commit](https://github.com/rails/rails/commit/0ffe19056c8e8b2f9ae9d487b896cad2ce9387ad)) - The ActiveRecord session store is extracted to a separate gem. Storing sessions in SQL is costly. Instead, use cookie sessions, memcache sessions, or a custom session store.
- * **ActiveModel mass assignment protection** ([commit](https://github.com/rails/rails/commit/f8c9a4d3e88181cee644f91e1342bfe896ca64c6)) - Rails 3 mass assignment protection is deprecated. Instead, use strong parameters.
- * **ActiveResource** ([commit](https://github.com/rails/rails/commit/f1637bf2bb00490203503fbd943b73406e043d1d)) - ActiveResource is extracted to a separate gem. ActiveResource was not widely used.
- * **vendor/plugins removed** ([commit](https://github.com/rails/rails/commit/853de2bd9ac572735fa6cf59fcf827e485a231c3)) - Use a Gemfile to manage installed gems.
+* **Ruby 1.9.3** ([commit](https://github.com/rails/rails/commit/a0380e808d3dbd2462df17f5d3b7fcd8bd812496)) - Ruby 2.0 preferred; 1.9.3+ required
+* **[New deprecation policy](http://www.youtube.com/watch?v=z6YgD6tVPQs)** - Deprecated features are warnings in Rails 4.0 and will be removed in Rails 4.1.
+* **ActionPack page and action caching** ([commit](https://github.com/rails/rails/commit/b0a7068564f0c95e7ef28fc39d0335ed17d93e90)) - Page and action caching are extracted to a separate gem. Page and action caching requires too much manual intervention (manually expiring caches when the underlying model objects are updated). Instead, use Russian doll caching.
+* **ActiveRecord observers** ([commit](https://github.com/rails/rails/commit/ccecab3ba950a288b61a516bf9b6962e384aae0b)) - Observers are extracted to a separate gem. Observers are only needed for page and action caching, and can lead to spaghetti code.
+* **ActiveRecord session store** ([commit](https://github.com/rails/rails/commit/0ffe19056c8e8b2f9ae9d487b896cad2ce9387ad)) - The ActiveRecord session store is extracted to a separate gem. Storing sessions in SQL is costly. Instead, use cookie sessions, memcache sessions, or a custom session store.
+* **ActiveModel mass assignment protection** ([commit](https://github.com/rails/rails/commit/f8c9a4d3e88181cee644f91e1342bfe896ca64c6)) - Rails 3 mass assignment protection is deprecated. Instead, use strong parameters.
+* **ActiveResource** ([commit](https://github.com/rails/rails/commit/f1637bf2bb00490203503fbd943b73406e043d1d)) - ActiveResource is extracted to a separate gem. ActiveResource was not widely used.
+* **vendor/plugins removed** ([commit](https://github.com/rails/rails/commit/853de2bd9ac572735fa6cf59fcf827e485a231c3)) - Use a Gemfile to manage installed gems.
### ActionPack
- * **Strong parameters** ([commit](https://github.com/rails/rails/commit/a8f6d5c6450a7fe058348a7f10a908352bb6c7fc)) - Only allow whitelisted parameters to update model objects (`params.permit(:title, :text)`).
- * **Routing concerns** ([commit](https://github.com/rails/rails/commit/0dd24728a088fcb4ae616bb5d62734aca5276b1b)) - In the routing DSL, factor out common subroutes (`comments` from `/posts/1/comments` and `/videos/1/comments`).
- * **ActionController::Live** ([commit](https://github.com/rails/rails/commit/af0a9f9eefaee3a8120cfd8d05cbc431af376da3)) - Stream JSON with `response.stream`.
- * **Declarative ETags** ([commit](https://github.com/rails/rails/commit/ed5c938fa36995f06d4917d9543ba78ed506bb8d)) - Add controller-level etag additions that will be part of the action etag computation.
- * **[Russian doll caching](http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works)** ([commit](https://github.com/rails/rails/commit/4154bf012d2bec2aae79e4a49aa94a70d3e91d49)) - Cache nested fragments of views. Each fragment expires based on a set of dependencies (a cache key). The cache key is usually a template version number and a model object.
- * **Turbolinks** ([commit](https://github.com/rails/rails/commit/e35d8b18d0649c0ecc58f6b73df6b3c8d0c6bb74)) - Serve only one initial HTML page. When the user navigates to another page, use pushState to update the URL and use AJAX to update the title and body.
- * **Decouple ActionView from ActionController** ([commit](https://github.com/rails/rails/commit/78b0934dd1bb84e8f093fb8ef95ca99b297b51cd)) - ActionView was decoupled from ActionPack and will be moved to a separated gem in Rails 4.1.
- * **Do not depend on ActiveModel** ([commit](https://github.com/rails/rails/commit/166dbaa7526a96fdf046f093f25b0a134b277a68)) - ActionPack no longer depends on ActiveModel.
+* **Strong parameters** ([commit](https://github.com/rails/rails/commit/a8f6d5c6450a7fe058348a7f10a908352bb6c7fc)) - Only allow whitelisted parameters to update model objects (`params.permit(:title, :text)`).
+* **Routing concerns** ([commit](https://github.com/rails/rails/commit/0dd24728a088fcb4ae616bb5d62734aca5276b1b)) - In the routing DSL, factor out common subroutes (`comments` from `/posts/1/comments` and `/videos/1/comments`).
+* **ActionController::Live** ([commit](https://github.com/rails/rails/commit/af0a9f9eefaee3a8120cfd8d05cbc431af376da3)) - Stream JSON with `response.stream`.
+* **Declarative ETags** ([commit](https://github.com/rails/rails/commit/ed5c938fa36995f06d4917d9543ba78ed506bb8d)) - Add controller-level etag additions that will be part of the action etag computation.
+* **[Russian doll caching](http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works)** ([commit](https://github.com/rails/rails/commit/4154bf012d2bec2aae79e4a49aa94a70d3e91d49)) - Cache nested fragments of views. Each fragment expires based on a set of dependencies (a cache key). The cache key is usually a template version number and a model object.
+* **Turbolinks** ([commit](https://github.com/rails/rails/commit/e35d8b18d0649c0ecc58f6b73df6b3c8d0c6bb74)) - Serve only one initial HTML page. When the user navigates to another page, use pushState to update the URL and use AJAX to update the title and body.
+* **Decouple ActionView from ActionController** ([commit](https://github.com/rails/rails/commit/78b0934dd1bb84e8f093fb8ef95ca99b297b51cd)) - ActionView was decoupled from ActionPack and will be moved to a separated gem in Rails 4.1.
+* **Do not depend on ActiveModel** ([commit](https://github.com/rails/rails/commit/166dbaa7526a96fdf046f093f25b0a134b277a68)) - ActionPack no longer depends on ActiveModel.
### General
@@ -95,9 +95,9 @@ NOTE: Check that the gems you are using are threadsafe.
### Security
- * **match do not catch all** ([commit](https://github.com/rails/rails/commit/90d2802b71a6e89aedfe40564a37bd35f777e541)) - In the routing DSL, match requires the HTTP verb or verbs to be specified.
- * **html entities escaped by default** ([commit](https://github.com/rails/rails/commit/5f189f41258b83d49012ec5a0678d827327e7543)) - Strings rendered in erb are escaped unless wrapped with `raw` or `html_safe` is called.
- * **New security headers** ([commit](https://github.com/rails/rails/commit/6794e92b204572d75a07bd6413bdae6ae22d5a82)) - Rails sends the following headers with every HTTP request: `X-Frame-Options` (prevents clickjacking by forbidding the browser from embedding the page in a frame), `X-XSS-Protection` (asks the browser to halt script injection) and `X-Content-Type-Options` (prevents the browser from opening a jpeg as an exe).
+* **match do not catch all** ([commit](https://github.com/rails/rails/commit/90d2802b71a6e89aedfe40564a37bd35f777e541)) - In the routing DSL, match requires the HTTP verb or verbs to be specified.
+* **html entities escaped by default** ([commit](https://github.com/rails/rails/commit/5f189f41258b83d49012ec5a0678d827327e7543)) - Strings rendered in erb are escaped unless wrapped with `raw` or `html_safe` is called.
+* **New security headers** ([commit](https://github.com/rails/rails/commit/6794e92b204572d75a07bd6413bdae6ae22d5a82)) - Rails sends the following headers with every HTTP request: `X-Frame-Options` (prevents clickjacking by forbidding the browser from embedding the page in a frame), `X-XSS-Protection` (asks the browser to halt script injection) and `X-Content-Type-Options` (prevents the browser from opening a jpeg as an exe).
Extraction of features to gems
---------------------------
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index 366d9d26b4..684bd286bc 100644
--- a/guides/source/4_2_release_notes.md
+++ b/guides/source/4_2_release_notes.md
@@ -257,7 +257,7 @@ application is using any of these spellings, you will need to update them:
* Values in attribute selectors may need to be quoted if they contain
non-alphanumeric characters.
- ```
+ ```ruby
# before
a[href=/]
a[href$=/]
@@ -272,7 +272,7 @@ application is using any of these spellings, you will need to update them:
For example:
- ``` ruby
+ ```ruby
# content: <div><i><p></i></div>
# before:
@@ -290,7 +290,7 @@ application is using any of these spellings, you will need to update them:
used to be raw (e.g. `AT&amp;T`), and now is evaluated
(e.g. `AT&T`).
- ``` ruby
+ ```ruby
# content: <p>AT&amp;T</p>
# before:
@@ -302,6 +302,30 @@ application is using any of these spellings, you will need to update them:
assert_select('p', 'AT&amp;T') # => false
```
+Furthermore substitutions have changed syntax.
+
+Now you have to use a `:match` CSS-like selector:
+
+```ruby
+assert_select ":match('id', ?)", 'comment_1'
+```
+
+Additionally Regexp substitutions look different when the assertion fails.
+Notice how `/hello/` here:
+
+```ruby
+assert_select(":match('id', ?)", /hello/)
+```
+
+becomes `"(?-mix:hello)"`:
+
+```
+Expected at least 1 element matching "div:match('id', "(?-mix:hello)")", found 0..
+Expected 0 to be >= 1.
+```
+
+See the [Rails Dom Testing](https://github.com/rails/rails-dom-testing/tree/8798b9349fb9540ad8cb9a0ce6cb88d1384a210b) documentation for more on `assert_select`.
+
Railties
--------
diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md
index a2b7b7a818..de8bbc4174 100644
--- a/guides/source/active_record_migrations.md
+++ b/guides/source/active_record_migrations.md
@@ -539,6 +539,14 @@ definitions:
`change_table` is also reversible, as long as the block does not call `change`,
`change_default` or `remove`.
+`remove_column` is reversible if you supply the column type as the third
+argument. Provide the original column options too, otherwise Rails can't
+recreate the column exactly when rolling back:
+
+```ruby
+remove_column :posts, :slug, :string, null: false, default: '', index: true
+```
+
If you're going to need to use any other methods, you should use `reversible`
or write the `up` and `down` methods instead of using the `change` method.
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index bef903b751..d6f3506aa5 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -1343,7 +1343,7 @@ Client.unscoped {
Dynamic Finders
---------------
-For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called `first_name` on your `Client` model for example, you get `find_by_first_name` for free from Active Record. If you have a `locked` field on the `Client` model, you also get `find_by_locked` and methods.
+For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called `first_name` on your `Client` model for example, you get `find_by_first_name` for free from Active Record. If you have a `locked` field on the `Client` model, you also get `find_by_locked` method.
You can specify an exclamation point (`!`) on the end of the dynamic finders to get them to raise an `ActiveRecord::RecordNotFound` error if they do not return any records, like `Client.find_by_name!("Ryan")`
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index f19934fe89..d251c5c0b1 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -1055,7 +1055,9 @@ person.errors[:name]
### `errors.add`
-The `add` method lets you manually add messages that are related to particular attributes. You can use the `errors.full_messages` or `errors.to_a` methods to view the messages in the form they might be displayed to a user. Those particular messages get the attribute name prepended (and capitalized). `add` receives the name of the attribute you want to add the message to, and the message itself.
+The `add` method lets you add an error message related to a particular attribute. It takes as arguments the attribute and the error message.
+
+The `errors.full_messages` method (or its equivalent, `errors.to_a`) returns the error messages in a user-friendly format, with the capitalized attribute name prepended to each message, as shown in the examples below.
```ruby
class Person < ActiveRecord::Base
@@ -1073,12 +1075,12 @@ person.errors.full_messages
# => ["Name cannot contain the characters !@#%*()_-+="]
```
-Another way to do this is using `[]=` setter
+An equivalent to `errors#add` is to use `<<` to append a message to the `errors.messages` array for an attribute:
```ruby
class Person < ActiveRecord::Base
def a_method_used_for_validation_purposes
- errors.add(:name, "cannot contain the characters !@#%*()_-+=")
+ errors.messages[:name] << "cannot contain the characters !@#%*()_-+="
end
end
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index 816bff3784..9da0ef1eb3 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -667,8 +667,7 @@ anymore, delete these options from the `javascript_include_tag` and
`stylesheet_link_tag`.
The fingerprinting behavior is controlled by the `config.assets.digest`
-initialization option (which defaults to `true` for production and `false` for
-everything else).
+initialization option (which defaults to `true` for production and development).
NOTE: Under normal circumstances the default `config.assets.digest` option
should not be changed. If there are no digests in the filenames, and far-future
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index d153e0bfa6..b409f20122 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -402,7 +402,7 @@ INFO: You can also use `rake -T` to get the list of tasks.
$ bin/rake about
About your application's environment
Rails version 5.0.0
-Ruby version 2.2.0 (x86_64-linux)
+Ruby version 2.2.1 (x86_64-linux)
RubyGems version 2.4.5
Rack version 1.6
JavaScript Runtime Node.js (V8)
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 67285030a9..6f32e6484f 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -309,6 +309,11 @@ All these configuration options are delegated to the `I18n` library.
* `config.active_record.belongs_to_required_by_default` is a boolean value and controls whether `belongs_to` association is required by default.
+* `config.active_record.warn_on_records_fetched_greater_than` allows setting a
+ warning threshold for query result size. If the number of records returned
+ by a query exceeds the threshold, a warning is logged. This can be used to
+ identify queries which might be causing memory bloat.
+
The MySQL adapter adds one additional configuration option:
* `ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns in a MySQL database to be booleans and is true by default.
diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md
index 2b71b5e04e..853227e2a1 100644
--- a/guides/source/form_helpers.md
+++ b/guides/source/form_helpers.md
@@ -241,7 +241,7 @@ Upon form submission the value entered by the user will be stored in `params[:pe
WARNING: You must pass the name of an instance variable, i.e. `:person` or `"person"`, not an actual instance of your model object.
-Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the [Active Record Validations](./active_record_validations.html#displaying-validation-errors-in-views) guide.
+Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the [Active Record Validations](active_record_validations.html#displaying-validation-errors-in-views) guide.
### Binding a Form to an Object
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index fe01088b2e..922ec3922e 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -1522,7 +1522,7 @@ This command will generate four files:
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| db/migrate/20140120201010_create_comments.rb | Migration to create the comments table in your database (your name will include a different timestamp) |
| app/models/comment.rb | The Comment model |
-| test/models/comment_test.rb | Testing harness for the comments model |
+| test/models/comment_test.rb | Testing harness for the comment model |
| test/fixtures/comments.yml | Sample comments for use in testing |
First, take a look at `app/models/comment.rb`:
diff --git a/guides/source/routing.md b/guides/source/routing.md
index 1a614fe42b..7d0a3efbe7 100644
--- a/guides/source/routing.md
+++ b/guides/source/routing.md
@@ -909,7 +909,7 @@ The `:as` option lets you override the normal naming for the named route helpers
resources :photos, as: 'images'
```
-will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the :as option to name the helpers.
+will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the `:as` option to name the helpers.
| HTTP Verb | Path | Controller#Action | Named Helper |
| --------- | ---------------- | ----------------- | -------------------- |
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 008a485720..752ef48b16 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -59,9 +59,9 @@ You can find comprehensive documentation in the [Fixtures API documentation](htt
#### What Are Fixtures?
-_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent written in YAML. There is one file per model.
+_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and written in YAML. There is one file per model.
-You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model fixture stubs will be automatically created and placed in this directory.
+You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model, Rails automatically creates fixture stubs in this directory.
#### YAML
@@ -162,7 +162,7 @@ project is created.
We will cover each of types Rails tests listed above in this guide.
-Unit Testing your Models
+Model Testing
------------------------
In Rails, unit tests are what you write to test your models.
@@ -929,7 +929,7 @@ assert_select_email do
end
```
-Testing helpers
+Testing Helpers
---------------
In order to test helpers, all you need to do is check that the output of the
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 0e9ef966ea..a181823576 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Respect `pluralize_table_names` when generating fixture file.
+
+ Fixes #19519.
+
+ *Yuji Yaginuma*
+
* Add a new-line to the end of route method generated code.
We need to add a `\n`, because we cannot have two routes
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 36456e64f5..01a8e2e9b4 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -141,6 +141,10 @@ module Rails
@plural_file_name ||= file_name.pluralize
end
+ def fixture_file_name
+ @fixture_file_name ||= (pluralize_table_names? ? plural_file_name : file_name)
+ end
+
def route_url
@route_url ||= class_path.collect {|dname| "/" + dname }.join + "/" + plural_file_name
end
diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb
index 2826a3ffa1..086588750e 100644
--- a/railties/lib/rails/generators/test_unit/model/model_generator.rb
+++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb
@@ -19,7 +19,7 @@ module TestUnit # :nodoc:
def create_fixture_file
if options[:fixture] && options[:fixture_replacement].nil?
- template 'fixtures.yml', File.join('test/fixtures', class_path, "#{plural_file_name}.yml")
+ template 'fixtures.yml', File.join('test/fixtures', class_path, "#{fixture_file_name}.yml")
end
end
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
index 17a13fbf1f..abd3ff50a4 100644
--- a/railties/test/generators/model_generator_test.rb
+++ b/railties/test/generators/model_generator_test.rb
@@ -319,6 +319,16 @@ class ModelGeneratorTest < Rails::Generators::TestCase
assert_no_file "test/fixtures/accounts.yml"
end
+ def test_fixture_without_pluralization
+ original_pluralize_table_name = ActiveRecord::Base.pluralize_table_names
+ ActiveRecord::Base.pluralize_table_names = false
+ run_generator
+ assert_generated_fixture("test/fixtures/account.yml",
+ {"one"=>{"name"=>"MyString", "age"=>1}, "two"=>{"name"=>"MyString", "age"=>1}})
+ ensure
+ ActiveRecord::Base.pluralize_table_names = original_pluralize_table_name
+ end
+
def test_check_class_collision
content = capture(:stderr){ run_generator ["object"] }
assert_match(/The name 'Object' is either already used in your application or reserved/, content)