aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile12
-rw-r--r--actionmailer/lib/action_mailer/base.rb6
-rw-r--r--actionpack/lib/abstract_controller/base.rb5
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb72
-rw-r--r--actionpack/lib/action_controller/base.rb13
-rw-r--r--actionpack/lib/action_controller/metal/force_ssl.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb32
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb6
-rw-r--r--actionpack/test/controller/filters_test.rb2
-rw-r--r--actionpack/test/dispatch/response_test.rb5
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/cache_helper.rb2
-rw-r--r--actionview/lib/action_view/rendering.rb26
-rw-r--r--activerecord/CHANGELOG.md4
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_association.rb4
-rw-r--r--activerecord/lib/active_record/associations/builder/association.rb2
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb4
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb1
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/reflection.rb1
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb3
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb51
-rw-r--r--activerecord/lib/active_record/relation/merger.rb6
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb29
-rw-r--r--activerecord/lib/active_record/result.rb16
-rw-r--r--activerecord/lib/active_record/scoping/default.rb6
-rw-r--r--activerecord/test/cases/associations/eager_test.rb7
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb18
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb30
-rw-r--r--activerecord/test/cases/associations/nested_through_associations_test.rb2
-rw-r--r--activerecord/test/cases/base_test.rb29
-rw-r--r--activerecord/test/cases/dup_test.rb2
-rw-r--r--activerecord/test/cases/relation_test.rb32
-rw-r--r--activerecord/test/cases/relations_test.rb18
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb2
-rw-r--r--guides/source/asset_pipeline.md4
-rw-r--r--guides/source/development_dependencies_install.md15
-rw-r--r--guides/source/migrations.md9
-rw-r--r--railties/lib/rails/engine/railties.rb2
-rw-r--r--railties/lib/rails/generators/rails/controller/controller_generator.rb6
-rw-r--r--railties/lib/rails/railtie/configuration.rb2
-rw-r--r--railties/test/application/configuration_test.rb7
-rw-r--r--railties/test/generators/namespaced_generators_test.rb2
43 files changed, 324 insertions, 179 deletions
diff --git a/Gemfile b/Gemfile
index d703a2e404..7ac743cbd6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -61,12 +61,12 @@ platforms :ruby do
end
platforms :jruby do
- git 'git://github.com/jruby/activerecord-jdbc-adapter.git' do
- gem 'activerecord-jdbcsqlite3-adapter'
- group :db do
- gem 'activerecord-jdbcmysql-adapter'
- gem 'activerecord-jdbcpostgresql-adapter'
- end
+ gem 'json'
+ gem 'activerecord-jdbcsqlite3-adapter', '>= 1.3.0'
+
+ group :db do
+ gem 'activerecord-jdbcmysql-adapter', '>= 1.3.0'
+ gem 'activerecord-jdbcpostgresql-adapter', '>= 1.3.0'
end
end
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 9dcd4bf554..ada86fbc4f 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -373,6 +373,8 @@ module ActionMailer
include AbstractController::AssetPaths
include AbstractController::Callbacks
+ self.protected_instance_variables = [:@_action_has_layout]
+
helper ActionMailer::MailHelper
private_class_method :new #:nodoc:
@@ -385,10 +387,6 @@ module ActionMailer
parts_order: [ "text/plain", "text/enriched", "text/html" ]
}.freeze
- def self.default_protected_instance_vars
- super.concat [:@_action_has_layout]
- end
-
class << self
# Register one or more Observers which will be notified when mail is delivered.
def register_observers(*observers)
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index a84ed17bd4..af5de815bb 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -114,11 +114,6 @@ module AbstractController
end
end
- # Define some internal variables that should not be propagated to the view.
- def self.default_protected_instance_vars
- []
- end
-
abstract!
# Calls the action going through the entire action dispatch stack.
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 41f19fba78..4596aad46c 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -13,8 +13,15 @@ module AbstractController
module Rendering
extend ActiveSupport::Concern
- def self.default_protected_instance_vars
- super.concat [:@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config]
+ included do
+ class_attribute :protected_instance_variables
+ self.protected_instance_variables = []
+ end
+
+ # Normalize arguments, options and then delegates render_to_body and
+ # sticks the result in self.response_body.
+ # :api: public
+ def render(*args, &block)
end
# Raw rendering of a template to a string.
@@ -29,32 +36,37 @@ module AbstractController
# overridden in order to still return a string.
# :api: plugin
def render_to_string(*args, &block)
+ options = _normalize_render(*args, &block)
+ render_to_body(options)
end
# Raw rendering of a template.
- # :api: plugin
- def render_to_body(options = {})
- end
-
- # Normalize arguments, options and then delegates render_to_body and
- # sticks the result in self.response_body.
# :api: public
- def render(*args, &block)
+ def render_to_body(options = {})
+ _process_options(options)
+ _render_template(options)
end
# Return Content-Type of rendered content
# :api: public
def rendered_format
+ Mime::TEXT
end
+ DEFAULT_PROTECTED_INSTANCE_VARIABLES = %w(
+ @_action_name @_response_body @_formats @_prefixes @_config
+ @_view_context_class @_view_renderer @_lookup_context
+ )
+
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
# :api: public
def view_assigns
hash = {}
- (instance_variables - self.class.default_protected_instance_vars).each do |name|
- hash[name[1..-1]] = instance_variable_get(name)
- end
+ variables = instance_variables
+ variables -= protected_instance_variables
+ variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES
+ variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) }
hash
end
@@ -76,5 +88,41 @@ module AbstractController
def _process_options(options)
options
end
+
+ # Normalize args and options.
+ # :api: private
+ def _normalize_render(*args, &block)
+ options = _normalize_args(*args, &block)
+ _normalize_options(options)
+ options
+ end
+ end
+
+ # Basic rendering implements the most minimal rendering layer.
+ # It only supports rendering :text and :nothing. Passing any other option will
+ # result in `UnsupportedOperationError` exception. For more functionality like
+ # different formats, layouts etc. you should use `ActionView` gem.
+ module BasicRendering
+ extend ActiveSupport::Concern
+
+ # Render text or nothing (empty string) to response_body
+ # :api: public
+ def render(*args, &block)
+ super(*args, &block)
+ opts = args.first
+ if opts.has_key?(:text) && opts[:text].present?
+ self.response_body = opts[:text]
+ elsif opts.has_key?(:nothing) && opts[:nothing]
+ self.response_body = " "
+ else
+ raise UnsupportedOperationError
+ end
+ end
+
+ class UnsupportedOperationError < StandardError
+ def initialize
+ super "Unsupported render operation. BasicRendering supports only :text and :nothing options. For more, you need to include ActionView."
+ end
+ end
end
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index a00eafc9ed..df416908f0 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -14,7 +14,7 @@ module ActionController
#
metal = Class.new(Metal) do
include AbstractController::Rendering
- include ActionController::BasicRendering
+ include AbstractController::BasicRendering
end
# Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed
@@ -261,12 +261,11 @@ module ActionController
include mod
end
- def self.default_protected_instance_vars
- super.concat [
- :@_status, :@_headers, :@_params, :@_env, :@_response, :@_request,
- :@_view_runtime, :@_stream, :@_url_options, :@_action_has_layout
- ]
- end
+ # Define some internal variables that should not be propagated to the view.
+ self.protected_instance_variables = [
+ :@_status, :@_headers, :@_params, :@_env, :@_response, :@_request,
+ :@_view_runtime, :@_stream, :@_url_options, :@_action_has_layout
+ ]
ActiveSupport.run_load_hooks(:action_controller, self)
end
diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb
index b8afce42c9..a2cb6d1e66 100644
--- a/actionpack/lib/action_controller/metal/force_ssl.rb
+++ b/actionpack/lib/action_controller/metal/force_ssl.rb
@@ -48,7 +48,7 @@ module ActionController
# You can pass any of the following options to affect the redirect status and response
# * <tt>status</tt> - Redirect with a custom status (default is 301 Moved Permanently)
# * <tt>flash</tt> - Set a flash message when redirecting
- # * <tt>alert</tt> - Set a alert message when redirecting
+ # * <tt>alert</tt> - Set an alert message when redirecting
# * <tt>notice</tt> - Set a notice message when redirecting
#
# ==== Action Options
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 21224b9c3b..abcc9d4acf 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -1,36 +1,4 @@
module ActionController
- # Basic rendering implements the most minimal rendering layer.
- # It only supports rendering :text and :nothing. Passing any other option will
- # result in `UnsupportedOperationError` exception. For more functionality like
- # different formats, layouts etc. you should use `ActionView` gem.
- module BasicRendering
- extend ActiveSupport::Concern
-
- # Render text or nothing (empty string) to response_body
- # :api: public
- def render(*args, &block)
- super(*args, &block)
- opts = args.first
- if opts.has_key?(:text) && opts[:text].present?
- self.response_body = opts[:text]
- elsif opts.has_key?(:nothing) && opts[:nothing]
- self.response_body = " "
- else
- raise UnsupportedOperationError
- end
- end
-
- def rendered_format
- Mime::TEXT
- end
-
- class UnsupportedOperationError < StandardError
- def initialize
- super "Unsupported render operation. BasicRendering supports only :text and :nothing options. For more, you need to include ActionView."
- end
- end
- end
-
module Rendering
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index d3696cbb8a..5247e61a23 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -41,7 +41,7 @@ module ActionDispatch # :nodoc:
# Get and set headers for this response.
attr_accessor :header
-
+
alias_method :headers=, :header=
alias_method :headers, :header
@@ -181,9 +181,9 @@ module ActionDispatch # :nodoc:
end
alias_method :status_message, :message
- def respond_to?(method)
+ def respond_to?(method, include_private = false)
if method.to_s == 'to_path'
- stream.respond_to?(:to_path)
+ stream.respond_to?(method)
else
super
end
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index e58a1aadb8..3b5d7ef446 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -17,7 +17,7 @@ class ActionController::Base
def assigns(key = nil)
assigns = {}
instance_variables.each do |ivar|
- next if ActionController::Base.default_protected_instance_vars.include?(ivar)
+ next if ActionController::Base.protected_instance_variables.include?(ivar)
assigns[ivar[1..-1]] = instance_variable_get(ivar)
end
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 2fbe7358f9..4501ea095c 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -212,6 +212,11 @@ class ResponseTest < ActiveSupport::TestCase
ActionDispatch::Response.default_headers = nil
end
end
+
+ test "respond_to? accepts include_private" do
+ assert_not @response.respond_to?(:method_missing)
+ assert @response.respond_to?(:method_missing, true)
+ end
end
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index 0b957adb91..c830ab23e3 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -143,9 +143,9 @@ module ActionView
"#{source}#{tail}"
end
- alias_method :path_to_asset, :asset_path # aliased to avoid conflicts with a asset_path named route
+ alias_method :path_to_asset, :asset_path # aliased to avoid conflicts with an asset_path named route
- # Computes the full URL to a asset in the public directory. This
+ # Computes the full URL to an asset in the public directory. This
# will use +asset_path+ internally, so most of their behaviors
# will be the same.
def asset_url(source, options = {})
diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb
index 2a38e5c446..b3af1d4da4 100644
--- a/actionview/lib/action_view/helpers/cache_helper.rb
+++ b/actionview/lib/action_view/helpers/cache_helper.rb
@@ -4,7 +4,7 @@ module ActionView
module CacheHelper
# This helper exposes a method for caching fragments of a view
# rather than an entire action or page. This technique is useful
- # caching pieces like menus, lists of newstopics, static HTML
+ # caching pieces like menus, lists of new topics, static HTML
# fragments, and so on. This method takes a block that contains
# the content you wish to cache.
#
diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb
index db9c4ef501..c1945cc0c5 100644
--- a/actionview/lib/action_view/rendering.rb
+++ b/actionview/lib/action_view/rendering.rb
@@ -84,20 +84,6 @@ module ActionView
self.response_body = render_to_body(options)
end
- # Raw rendering of a template to a string.
- # :api: public
- def render_to_string(*args, &block)
- options = _normalize_render(*args, &block)
- render_to_body(options)
- end
-
- # Raw rendering of a template.
- # :api: public
- def render_to_body(options = {})
- _process_options(options)
- _render_template(options)
- end
-
# Find and renders a template based on the options given.
# :api: private
def _render_template(options) #:nodoc:
@@ -109,20 +95,8 @@ module ActionView
Mime[lookup_context.rendered_format]
end
- def default_protected_instance_vars
- super.concat([:@_view_context_class, :@_view_renderer, :@_lookup_context])
- end
-
private
- # Normalize args and options.
- # :api: private
- def _normalize_render(*args, &block)
- options = _normalize_args(*args, &block)
- _normalize_options(options)
- options
- end
-
# Normalize args by converting render "foo" to render :action => "foo" and
# render "foo/bar" to render :file => "foo/bar".
# :api: private
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index c7928e503b..b79b9a87c6 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Re-use `order` argument pre-processing for `reorder`.
+
+ *Paul Nikitochkin*
+
* Fix PredicateBuilder so polymorhic association keys in `where` clause can
also accept not only `ActiveRecord::Base` direct descendances (decorated
models, for example).
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb
index 8eec4f56af..e1fa5225b5 100644
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb
@@ -50,8 +50,8 @@ module ActiveRecord
# Checks whether record is different to the current target, without loading it
def different_target?(record)
- if record.nil?
- owner[reflection.foreign_key]
+ if record.nil?
+ owner[reflection.foreign_key]
else
record.id != owner[reflection.foreign_key]
end
diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb
index 34de1a1f32..1059fc032d 100644
--- a/activerecord/lib/active_record/associations/builder/association.rb
+++ b/activerecord/lib/active_record/associations/builder/association.rb
@@ -17,7 +17,7 @@ module ActiveRecord::Associations::Builder
end
self.extensions = []
- VALID_OPTIONS = [:class_name, :foreign_key, :validate]
+ VALID_OPTIONS = [:class_name, :class, :foreign_key, :validate]
attr_reader :name, :scope, :options
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index 2317e34bc0..6cc9d6c079 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -85,9 +85,11 @@ module ActiveRecord
def initialize(records, associations, preload_scope = nil)
@records = Array.wrap(records).compact.uniq
@associations = Array.wrap(associations)
- @preload_scope = preload_scope || Relation.create(nil, nil)
+ @preload_scope = preload_scope || NULL_RELATION
end
+ NULL_RELATION = Struct.new(:values).new({})
+
def run
unless records.empty?
associations.each { |association| preload(association) }
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index 10238555f0..02dc464536 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -42,7 +42,6 @@ module ActiveRecord
scope.first.tap { |record| set_inverse_instance(record) }
end
- # Implemented by subclasses
def replace(record)
raise NotImplementedError, "Subclasses must implement a replace(record) method"
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index b06add096f..04e3dd49e7 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -18,6 +18,7 @@ require 'arel'
require 'active_record/errors'
require 'active_record/log_subscriber'
require 'active_record/explain_subscriber'
+require 'active_record/relation/delegation'
module ActiveRecord #:nodoc:
# = Active Record
@@ -290,6 +291,7 @@ module ActiveRecord #:nodoc:
extend Translation
extend DynamicMatchers
extend Explain
+ extend Delegation::DelegateCache
include Persistence
include ReadonlyAttributes
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 5245fc130a..150a90f5db 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -121,6 +121,7 @@ module ActiveRecord
@scope = scope
@options = options
@active_record = active_record
+ @klass = options[:class]
@plural_name = active_record.pluralize_table_names ?
name.to_s.pluralize : name.to_s
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 52a538e5b5..27c04b0952 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -161,8 +161,7 @@ module ActiveRecord
result = result.map do |attributes|
values = klass.initialize_attributes(attributes).values
- iter = columns.each
- values.map { |value| iter.next.type_cast value }
+ columns.zip(values).map { |column, value| column.type_cast value }
end
columns.one? ? result.map!(&:first) : result
end
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index b6f80ac5c7..e28938f9d0 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -1,8 +1,33 @@
-require 'thread'
-require 'thread_safe'
+require 'active_support/concern'
module ActiveRecord
module Delegation # :nodoc:
+ module DelegateCache
+ def relation_delegate_class(klass) # :nodoc:
+ @relation_delegate_cache[klass]
+ end
+
+ def initialize_relation_delegate_cache # :nodoc:
+ @relation_delegate_cache = cache = {}
+ [
+ ActiveRecord::Relation,
+ ActiveRecord::Associations::CollectionProxy,
+ ActiveRecord::AssociationRelation
+ ].each do |klass|
+ delegate = Class.new(klass) {
+ include ClassSpecificRelation
+ }
+ const_set klass.name.gsub('::', '_'), delegate
+ cache[klass] = delegate
+ end
+ end
+
+ def inherited(child_class)
+ child_class.initialize_relation_delegate_cache
+ super
+ end
+ end
+
extend ActiveSupport::Concern
# This module creates compiled delegation methods dynamically at runtime, which makes
@@ -71,32 +96,14 @@ module ActiveRecord
end
module ClassMethods # :nodoc:
- @@subclasses = ThreadSafe::Cache.new(:initial_capacity => 2)
-
def create(klass, *args)
relation_class_for(klass).new(klass, *args)
end
private
- # Cache the constants in @@subclasses because looking them up via const_get
- # make instantiation significantly slower.
+
def relation_class_for(klass)
- if klass && (klass_name = klass.name)
- my_cache = @@subclasses.compute_if_absent(self) { ThreadSafe::Cache.new }
- # This hash is keyed by klass.name to avoid memory leaks in development mode
- my_cache.compute_if_absent(klass_name) do
- # Cache#compute_if_absent guarantees that the block will only executed once for the given klass_name
- subclass_name = "#{name.gsub('::', '_')}_#{klass_name.gsub('::', '_')}"
-
- if const_defined?(subclass_name)
- const_get(subclass_name)
- else
- const_set(subclass_name, Class.new(self) { include ClassSpecificRelation })
- end
- end
- else
- ActiveRecord::Relation
- end
+ klass.relation_delegate_class(self)
end
end
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index c08158d38b..530c47d0d0 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -107,11 +107,11 @@ module ActiveRecord
bind_values = filter_binds(lhs_binds, removed) + rhs_binds
conn = relation.klass.connection
- bviter = bind_values.each.with_index
+ bv_index = 0
where_values.map! do |node|
if Arel::Nodes::Equality === node && Arel::Nodes::BindParam === node.right
- (column, _), i = bviter.next
- substitute = conn.substitute_at column, i
+ substitute = conn.substitute_at(bind_values[bv_index].first, bv_index)
+ bv_index += 1
Arel::Nodes::Equality.new(node.left, substitute)
else
node
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 9f2a039d94..1c6ea94c0b 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -289,17 +289,7 @@ module ActiveRecord
end
def order!(*args) # :nodoc:
- args.flatten!
- validate_order_args(args)
-
- references = args.grep(String)
- references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
- references!(references) if references.any?
-
- # if a symbol is given we prepend the quoted table name
- args.map! do |arg|
- arg.is_a?(Symbol) ? Arel::Nodes::Ascending.new(klass.arel_table[arg]) : arg
- end
+ preprocess_order_args(args)
self.order_values += args
self
@@ -320,8 +310,7 @@ module ActiveRecord
end
def reorder!(*args) # :nodoc:
- args.flatten!
- validate_order_args(args)
+ preprocess_order_args(args)
self.reordering_value = true
self.order_values = args
@@ -1036,6 +1025,20 @@ module ActiveRecord
end
end
+ def preprocess_order_args(order_args)
+ order_args.flatten!
+ validate_order_args(order_args)
+
+ references = order_args.grep(String)
+ references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
+ references!(references) if references.any?
+
+ # if a symbol is given we prepend the quoted table name
+ order_args.map! do |arg|
+ arg.is_a?(Symbol) ? Arel::Nodes::Ascending.new(klass.arel_table[arg]) : arg
+ end
+ end
+
# Checks to make sure that the arguments are not blank. Note that if some
# blank-like object were initially passed into the query method, then this
# method will not raise an error.
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index 253368ae5b..d0f1cb5b75 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -93,7 +93,21 @@ module ActiveRecord
# used as keys in ActiveRecord::Base's @attributes hash
columns = @columns.map { |c| c.dup.freeze }
@rows.map { |row|
- Hash[columns.zip(row)]
+ # In the past we used Hash[columns.zip(row)]
+ # though elegant, the verbose way is much more efficient
+ # both time and memory wise cause it avoids a big array allocation
+ # this method is called a lot and needs to be micro optimised
+ hash = {}
+
+ index = 0
+ length = columns.length
+
+ while index < length
+ hash[columns[index]] = row[index]
+ index += 1
+ end
+
+ hash
}
end
end
diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb
index a5d6aad3f0..01fec31544 100644
--- a/activerecord/lib/active_record/scoping/default.rb
+++ b/activerecord/lib/active_record/scoping/default.rb
@@ -100,11 +100,7 @@ module ActiveRecord
elsif default_scopes.any?
evaluate_default_scope do
default_scopes.inject(relation) do |default_scope, scope|
- if !scope.is_a?(Relation) && scope.respond_to?(:call)
- default_scope.merge(unscoped { scope.call })
- else
- default_scope.merge(scope)
- end
+ default_scope.merge(unscoped { scope.call })
end
end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 28bf48f4fd..8d3d6962fc 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -1172,8 +1172,11 @@ class EagerAssociationTest < ActiveRecord::TestCase
}
end
- test "works in combination with order(:symbol)" do
- author = Author.includes(:posts).references(:posts).order(:name).where('posts.title IS NOT NULL').first
+ test "works in combination with order(:symbol) and reorder(:symbol)" do
+ author = Author.includes(:posts).references(:posts).order(:name).find_by('posts.title IS NOT NULL')
+ assert_equal authors(:bob), author
+
+ author = Author.includes(:posts).references(:posts).reorder(:name).find_by('posts.title IS NOT NULL')
assert_equal authors(:bob), author
end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index ce51853bf3..4c0fa88917 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -45,6 +45,24 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
Client.destroyed_client_ids.clear
end
+ def test_anonymous_has_many
+ developer = Class.new(ActiveRecord::Base) {
+ self.table_name = 'developers'
+ dev = self
+
+ developer_project = Class.new(ActiveRecord::Base) {
+ self.table_name = 'developers_projects'
+ belongs_to :developer, :class => dev
+ }
+ has_many :developer_projects, :class => developer_project, :foreign_key => 'developer_id'
+ }
+ dev = developer.first
+ named = Developer.find(dev.id)
+ assert_operator dev.developer_projects.count, :>, 0
+ assert_equal named.projects.map(&:id).sort,
+ dev.developer_projects.map(&:project_id).sort
+ end
+
def test_create_from_association_should_respect_default_scope
car = Car.create(:name => 'honda')
assert_equal 'honda', car.name
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 45087fdf8a..508faa9437 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -28,7 +28,8 @@ require 'models/club'
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
:owners, :pets, :toys, :jobs, :references, :companies, :members, :author_addresses,
- :subscribers, :books, :subscriptions, :developers, :categorizations, :essays
+ :subscribers, :books, :subscriptions, :developers, :categorizations, :essays,
+ :categories_posts
# Dummies to force column loads so query counts are clean.
def setup
@@ -36,6 +37,33 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
Reader.create :person_id => 0, :post_id => 0
end
+ def make_model(name)
+ Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
+ end
+
+ def test_singleton_has_many_through
+ book = make_model "Book"
+ subscription = make_model "Subscription"
+ subscriber = make_model "Subscriber"
+
+ subscriber.primary_key = 'nick'
+ subscription.belongs_to :book, class: book
+ subscription.belongs_to :subscriber, class: subscriber
+
+ book.has_many :subscriptions, class: subscription
+ book.has_many :subscribers, through: :subscriptions, class: subscriber
+
+ anonbook = book.first
+ namebook = Book.find anonbook.id
+
+ assert_operator anonbook.subscribers.count, :>, 0
+ anonbook.subscribers.each do |s|
+ assert_instance_of subscriber, s
+ end
+ assert_equal namebook.subscribers.map(&:id).sort,
+ anonbook.subscribers.map(&:id).sort
+ end
+
def test_pk_is_not_required_for_join
post = Post.includes(:scategories).first
post2 = Post.includes(:categories).first
diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb
index 9b1abc3b81..cf3c07845c 100644
--- a/activerecord/test/cases/associations/nested_through_associations_test.rb
+++ b/activerecord/test/cases/associations/nested_through_associations_test.rb
@@ -371,7 +371,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
prev_default_scope = Club.default_scopes
[:includes, :preload, :joins, :eager_load].each do |q|
- Club.default_scopes = [Club.send(q, :category)]
+ Club.default_scopes = [proc { Club.send(q, :category) }]
assert_equal categories(:general), members(:groucho).reload.club_category
end
ensure
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index c91cf89f6d..dc2de7b523 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1324,6 +1324,35 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal 1, post.comments.length
end
+ def test_marshal_between_processes
+ skip "fork isn't supported" unless Process.respond_to?(:fork)
+
+ # Define a new model to ensure there are no caches
+ if self.class.const_defined?("Post", false)
+ flunk "there should be no post constant"
+ end
+
+ self.class.const_set("Post", Class.new(ActiveRecord::Base) {
+ has_many :comments
+ })
+
+ rd, wr = IO.pipe
+
+ ActiveRecord::Base.connection_handler.clear_all_connections!
+
+ fork do
+ rd.close
+ post = Post.new
+ post.comments.build
+ wr.write Marshal.dump(post)
+ wr.close
+ end
+
+ wr.close
+ assert Marshal.load rd.read
+ rd.close
+ end
+
def test_marshalling_new_record_round_trip_with_associations
post = Post.new
post.comments.build
diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb
index f73e449610..1e6ccecfab 100644
--- a/activerecord/test/cases/dup_test.rb
+++ b/activerecord/test/cases/dup_test.rb
@@ -126,7 +126,7 @@ module ActiveRecord
def test_dup_with_default_scope
prev_default_scopes = Topic.default_scopes
- Topic.default_scopes = [Topic.where(:approved => true)]
+ Topic.default_scopes = [proc { Topic.where(:approved => true) }]
topic = Topic.new(:approved => false)
assert !topic.dup.approved?, "should not be overridden by default scopes"
ensure
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index f99801c437..a327b0d3e5 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -9,6 +9,10 @@ module ActiveRecord
fixtures :posts, :comments, :authors
class FakeKlass < Struct.new(:table_name, :name)
+ extend ActiveRecord::Delegation::DelegateCache
+
+ inherited self
+
def self.connection
Post.connection
end
@@ -76,8 +80,8 @@ module ActiveRecord
end
def test_table_name_delegates_to_klass
- relation = Relation.new FakeKlass.new('foo'), :b
- assert_equal 'foo', relation.table_name
+ relation = Relation.new FakeKlass.new('posts'), :b
+ assert_equal 'posts', relation.table_name
end
def test_scope_for_create
@@ -177,8 +181,12 @@ module ActiveRecord
end
test 'merging a hash interpolates conditions' do
- klass = stub_everything
- klass.stubs(:sanitize_sql).with(['foo = ?', 'bar']).returns('foo = bar')
+ klass = Class.new(FakeKlass) do
+ def self.sanitize_sql(args)
+ raise unless args == ['foo = ?', 'bar']
+ 'foo = bar'
+ end
+ end
relation = Relation.new(klass, :b)
relation.merge!(where: ['foo = ?', 'bar'])
@@ -210,6 +218,9 @@ module ActiveRecord
class RelationMutationTest < ActiveSupport::TestCase
class FakeKlass < Struct.new(:table_name, :name)
+ extend ActiveRecord::Delegation::DelegateCache
+ inherited self
+
def arel_table
Post.arel_table
end
@@ -217,6 +228,10 @@ module ActiveRecord
def connection
Post.connection
end
+
+ def relation_delegate_class(klass)
+ self.class.relation_delegate_class(klass)
+ end
end
def relation
@@ -296,6 +311,15 @@ module ActiveRecord
assert relation.reordering_value
end
+ test '#reorder! with symbol prepends the table name' do
+ assert relation.reorder!(:name).equal?(relation)
+ node = relation.order_values.first
+
+ assert node.ascending?
+ assert_equal :name, node.expr.name
+ assert_equal "posts", node.expr.relation.name
+ end
+
test 'reverse_order!' do
assert relation.reverse_order!.equal?(relation)
assert relation.reverse_order_value
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index e1a760d240..b3ca45c4c8 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -1344,6 +1344,24 @@ class RelationTest < ActiveRecord::TestCase
assert_equal [], scope.references_values
end
+ def test_automatically_added_reorder_references
+ scope = Post.reorder('comments.body')
+ assert_equal %w(comments), scope.references_values
+
+ scope = Post.reorder('comments.body', 'yaks.body')
+ assert_equal %w(comments yaks), scope.references_values
+
+ # Don't infer yaks, let's not go down that road again...
+ scope = Post.reorder('comments.body, yaks.body')
+ assert_equal %w(comments), scope.references_values
+
+ scope = Post.reorder('comments.body asc')
+ assert_equal %w(comments), scope.references_values
+
+ scope = Post.reorder('foo(comments.body)')
+ assert_equal [], scope.references_values
+ end
+
def test_presence
topics = Topic.all
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index d063fcb49c..ffdb7b53c4 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -36,7 +36,7 @@ module ActiveSupport
# string.
#
# If passed an optional +locale+ parameter, the word will be
- # pluralized using rules defined for that language. By default,
+ # singularized using rules defined for that language. By default,
# this parameter is set to <tt>:en</tt>.
#
# 'posts'.singularize # => "post"
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index 8fa86cb516..72aff1e0dd 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -765,8 +765,8 @@ headers.
For Apache:
```apache
-# The Expires* directives requires the Apache module `mod_expires` to be
-# enabled.
+# The Expires* directives requires the Apache module
+# `mod_expires` to be enabled.
<Location /assets/>
# Use of ETag is discouraged when Last-Modified is present
Header unset ETag FileETag None
diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md
index 12b192fa87..c4e5789a1a 100644
--- a/guides/source/development_dependencies_install.md
+++ b/guides/source/development_dependencies_install.md
@@ -86,7 +86,6 @@ And if you are on Fedora or CentOS, you're done with
$ sudo yum install sqlite3 sqlite3-devel
```
-<<<<<<< HEAD
If you are on Arch Linux, you will need to run:
```bash
@@ -101,8 +100,6 @@ For FreeBSD users, you're done with:
Or compile the `databases/sqlite3` port.
-=======
->>>>>>> ec8ef1e1055c4e1598da13f49d30261f07f4a9b4
Get a recent version of [Bundler](http://gembundler.com/)
```bash
@@ -158,13 +155,20 @@ $ cd railties
$ TEST_DIR=generators bundle exec rake test
```
-You can run any single test separately too:
+You can run the tests for a particular file by using:
```bash
$ cd actionpack
$ bundle exec ruby -Itest test/template/form_helper_test.rb
```
+Or, you can run a single test in a particular file:
+
+```bash
+$ cd actionpack
+$ bundle exec ruby -Itest path/to/test.rb -n test_name
+```
+
### Active Record Setup
The test suite of Active Record attempts to run four times: once for SQLite3, once for each of the two MySQL gems (`mysql` and `mysql2`), and once for PostgreSQL. We are going to see now how to set up the environment for them.
@@ -191,7 +195,6 @@ $ sudo yum install mysql-server mysql-devel
$ sudo yum install postgresql-server postgresql-devel
```
-<<<<<<< HEAD
If you are running Arch Linux, MySQL isn't supported anymore so you will need to
use MariaDB instead (see [this announcement](https://www.archlinux.org/news/mariadb-replaces-mysql-in-repositories/)):
@@ -211,8 +214,6 @@ Or install them through ports (they are located under the `databases` folder).
If you run into troubles during the installation of MySQL, please see
[the MySQL documentation](http://dev.mysql.com/doc/refman/5.1/en/freebsd-installation.html).
-=======
->>>>>>> ec8ef1e1055c4e1598da13f49d30261f07f4a9b4
After that, run:
```bash
diff --git a/guides/source/migrations.md b/guides/source/migrations.md
index 6100fc89c8..414ce46a4e 100644
--- a/guides/source/migrations.md
+++ b/guides/source/migrations.md
@@ -692,10 +692,15 @@ Neither of these Rake tasks do anything you could not do with `db:migrate`. They
are simply more convenient, since you do not need to explicitly specify the
version to migrate to.
+### Setup the Database
+
+The `rake db:setup` task will create the database, load the schema and initialize
+it with the seed data.
+
### Resetting the Database
-The `rake db:reset` task will drop the database, recreate it and load the
-current schema into it.
+The `rake db:reset` task will drop the database and set it up again. This is
+functionally equivalent to `rake db:drop db:setup`.
NOTE: This is not the same as running all the migrations. It will only use the
contents of the current schema.rb file. If a migration can't be rolled back,
diff --git a/railties/lib/rails/engine/railties.rb b/railties/lib/rails/engine/railties.rb
index 595256f36a..9969a1475d 100644
--- a/railties/lib/rails/engine/railties.rb
+++ b/railties/lib/rails/engine/railties.rb
@@ -16,8 +16,6 @@ module Rails
def -(others)
_all - others
end
-
- delegate :engines, to: "self.class"
end
end
end
diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb
index 822f35fb42..ef84447df9 100644
--- a/railties/lib/rails/generators/rails/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb
@@ -32,18 +32,18 @@ module Rails
# namespace :foo do
# namespace :bar do
namespace_ladder = class_path.each_with_index.map do |ns, i|
- %{#{" " * i * 2}namespace :#{ns} do\n }
+ indent("namespace :#{ns} do\n", i * 2)
end.join
# Create route
# get "baz/index"
- route = %{#{" " * depth * 2}get "#{file_name}/#{action}"\n}
+ route = indent(%{get "#{file_name}/#{action}"\n}, depth * 2)
# Create `end` ladder
# end
# end
end_ladder = (1..depth).reverse_each.map do |i|
- "#{" " * i * 2}end\n"
+ indent("end\n", i * 2)
end.join
# Combine the 3 parts to generate complete route entry
diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb
index 0cbbf04da2..eb3b2d8ef4 100644
--- a/railties/lib/rails/railtie/configuration.rb
+++ b/railties/lib/rails/railtie/configuration.rb
@@ -80,7 +80,7 @@ module Rails
to_prepare_blocks << blk if blk
end
- def respond_to?(name)
+ def respond_to?(name, include_private = false)
super || @@options.key?(name.to_sym)
end
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index c51488e0e1..03a735b1c1 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -679,5 +679,12 @@ module ApplicationTests
end
assert_equal Logger::INFO, Rails.logger.level
end
+
+ test "respond_to? accepts include_private" do
+ make_basic_app
+
+ assert_not Rails.configuration.respond_to?(:method_missing)
+ assert Rails.configuration.respond_to?(:method_missing, true)
+ end
end
end
diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb
index a4d8b3d1b0..e17925ff65 100644
--- a/railties/test/generators/namespaced_generators_test.rb
+++ b/railties/test/generators/namespaced_generators_test.rb
@@ -44,7 +44,7 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase
end
end
- def test_helpr_is_also_namespaced
+ def test_helper_is_also_namespaced
run_generator
assert_file "app/helpers/test_app/account_helper.rb", /module TestApp/, / module AccountHelper/
assert_file "test/helpers/test_app/account_helper_test.rb", /module TestApp/, / class AccountHelperTest/