aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionmailer/actionmailer.gemspec2
-rw-r--r--actionmailer/test/mailers/base_mailer.rb2
-rw-r--r--actionpack/CHANGELOG.md69
-rw-r--r--actionpack/lib/action_controller/test_case.rb29
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb8
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb12
-rw-r--r--actionpack/lib/action_view/asset_paths.rb2
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb15
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionpack/lib/action_view/lookup_context.rb7
-rw-r--r--actionpack/lib/action_view/renderer/abstract_renderer.rb6
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb5
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb37
-rw-r--r--actionpack/test/dispatch/routing_test.rb13
-rw-r--r--actionpack/test/fixtures/test/_changing_priority.html.erb1
-rw-r--r--actionpack/test/fixtures/test/_changing_priority.json.erb1
-rw-r--r--actionpack/test/fixtures/test/_first_json_partial.json.erb1
-rw-r--r--actionpack/test/fixtures/test/_json_change_priority.json.erb0
-rw-r--r--actionpack/test/fixtures/test/_second_json_partial.json.erb1
-rw-r--r--actionpack/test/fixtures/test/change_priority.html.erb2
-rw-r--r--actionpack/test/fixtures/test/hello_world_with_partial.html.erb2
-rw-r--r--actionpack/test/fixtures/test/html_template.html.erb1
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb40
-rw-r--r--actionpack/test/template/date_helper_test.rb4
-rw-r--r--actionpack/test/template/form_helper_test.rb10
-rw-r--r--actionpack/test/template/render_test.rb10
-rw-r--r--actionpack/test/template/url_helper_test.rb5
-rw-r--r--activerecord/CHANGELOG.md98
-rw-r--r--activerecord/lib/active_record/associations/builder/belongs_to.rb5
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb3
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb7
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb3
-rw-r--r--activerecord/lib/active_record/autosave_association.rb19
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/explain_subscriber.rb2
-rw-r--r--activerecord/lib/active_record/model_schema.rb4
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb58
-rw-r--r--activerecord/lib/active_record/railtie.rb13
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb11
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb1
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb37
-rw-r--r--activerecord/lib/active_record/store.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/bytea_test.rb46
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb20
-rw-r--r--activerecord/test/cases/associations/eager_test.rb7
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb35
-rw-r--r--activerecord/test/cases/autosave_association_test.rb22
-rw-r--r--activerecord/test/cases/base_test.rb10
-rw-r--r--activerecord/test/cases/calculations_test.rb8
-rw-r--r--activerecord/test/cases/disconnected_test.rb26
-rw-r--r--activerecord/test/cases/explain_subscriber_test.rb7
-rw-r--r--activerecord/test/cases/finder_test.rb19
-rw-r--r--activerecord/test/cases/mass_assignment_security_test.rb10
-rw-r--r--activerecord/test/cases/relations_test.rb16
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb5
-rw-r--r--activerecord/test/cases/store_test.rb7
-rw-r--r--activerecord/test/models/person.rb1
-rw-r--r--activerecord/test/models/post.rb3
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb1
-rw-r--r--activeresource/CHANGELOG.md4
-rw-r--r--activeresource/lib/active_resource/base.rb2
-rw-r--r--activeresource/test/cases/base_test.rb16
-rw-r--r--activesupport/CHANGELOG.md11
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb12
-rw-r--r--activesupport/lib/active_support/json/encoding.rb8
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb22
-rw-r--r--activesupport/test/json/encoding_test.rb29
-rw-r--r--railties/CHANGELOG.md11
-rw-r--r--railties/guides/source/caching_with_rails.textile6
-rw-r--r--railties/guides/source/getting_started.textile2
-rw-r--r--railties/guides/source/initialization.textile2
-rw-r--r--railties/guides/source/layout.html.erb10
-rw-r--r--railties/lib/rails/application.rb11
-rw-r--r--railties/lib/rails/commands/runner.rb1
-rw-r--r--railties/lib/rails/engine.rb5
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb2
-rw-r--r--railties/lib/rails/railtie.rb10
-rw-r--r--railties/test/application/rake_test.rb22
-rw-r--r--railties/test/application/routing_test.rb24
-rw-r--r--railties/test/application/runner_test.rb10
-rw-r--r--railties/test/generators/scaffold_generator_test.rb16
-rw-r--r--railties/test/railties/railtie_test.rb16
89 files changed, 917 insertions, 150 deletions
diff --git a/Gemfile b/Gemfile
index 6098cf78a1..4b8def733c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -53,7 +53,7 @@ end
platforms :ruby do
gem 'yajl-ruby'
- gem 'nokogiri', '>= 1.4.5'
+ gem 'nokogiri', '>= 1.4.5', '< 1.6'
# AR
gem 'sqlite3', '~> 1.3.5'
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index c2c8e9b8e2..8b2e754fde 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -17,5 +17,5 @@ Gem::Specification.new do |s|
s.requirements << 'none'
s.add_dependency('actionpack', version)
- s.add_dependency('mail', '~> 2.5.3')
+ s.add_dependency('mail', '~> 2.5.4')
end
diff --git a/actionmailer/test/mailers/base_mailer.rb b/actionmailer/test/mailers/base_mailer.rb
index 50438ead2a..bd3f193fda 100644
--- a/actionmailer/test/mailers/base_mailer.rb
+++ b/actionmailer/test/mailers/base_mailer.rb
@@ -38,7 +38,7 @@ class BaseMailer < ActionMailer::Base
end
def attachment_with_hash
- attachments['invoice.jpg'] = { :data => "\312\213\254\232)b",
+ attachments['invoice.jpg'] = { :data => ::Base64.encode64("\312\213\254\232)b"),
:mime_type => "image/x-jpg",
:transfer_encoding => "base64" }
mail
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 1f4e356952..ac260a9592 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,28 +1,79 @@
## unreleased ##
-* Fixed assets loading performance in 3.2.13.
+* Merge `:action` from routing scope and assign endpoint if both `:controller`
+ and `:action` are present. The endpoint assignment only occurs if there is
+ no `:to` present in the options hash so should only affect routes using the
+ shorthand syntax (i.e. endpoint is inferred from the the path).
- #8756 uses Sprockets for resolving files that already exists on disk, for those files
- their extensions don't need to be rewritten.
+ Fixes #9856
+
+ *Yves Senn*, *Andrew White*
+
+* Always escape the result of `link_to_unless` method.
+
+ Before:
+
+ link_to_unless(true, '<b>Showing</b>', 'github.com')
+ # => "<b>Showing</b>"
+
+ After:
+
+ link_to_unless(true, '<b>Showing</b>', 'github.com')
+ # => "&lt;b&gt;Showing&lt;/b&gt;"
+
+ *dtaniwaki*
+
+* Use a case insensitive URI Regexp for #asset_path.
+
+ This fix a problem where the same asset path using different case are generating
+ different URIs.
+
+ Before:
+
+ image_tag("HTTP://google.com")
+ # => "<img alt=\"Google\" src=\"/assets/HTTP://google.com\" />"
+ image_tag("http://google.com")
+ # => "<img alt=\"Google\" src=\"http://google.com\" />"
+
+ After:
+
+ image_tag("HTTP://google.com")
+ # => "<img alt=\"Google\" src=\"HTTP://google.com\" />"
+ image_tag("http://google.com")
+ # => "<img alt=\"Google\" src=\"http://google.com\" />"
+
+ *David Celis + Rafael Mendonça França*
+
+* Fix explicit names on multiple file fields. If a file field tag has
+ the multiple option, it is turned into an array field (appending `[]`),
+ but if an explicit name is passed to `file_field` the `[]` is not
+ appended.
+ Fixes #9830.
+
+ *Ryan McGeary*
+
+* Fix assets loading performance in 3.2.13.
+
+ Issue #8756 uses Sprockets for resolving files that already exist on disk,
+ for those files their extensions don't need to be rewritten.
Fixes #9803.
*Fred Wu*
-* Fixed `ActionController#action_missing` not being called.
-
+* Fix `ActionController#action_missing` not being called.
Fixes #9799.
*Janko Luin*
-* `ActiveSupport::NumberHelper#number_to_human` returns the number unaltered when
+* `ActionView::Helpers::NumberHelper#number_to_human` returns the number unaltered when
the units hash does not contain the needed key, e.g. when the number provided is less
- than the largest key proivided.
+ than the largest key provided.
Examples:
- number_to_human(123, :units => {}) # => 123
- number_to_human(123, :units => {:thousand => 'k'}) # => 123
+ number_to_human(123, units: {}) # => 123
+ number_to_human(123, units: { thousand: 'k' }) # => 123
Fixes #9269.
Backport #9347.
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index bc6828a805..e089feea87 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -20,7 +20,12 @@ module ActionController
ActiveSupport::Notifications.subscribe("render_template.action_view") do |name, start, finish, id, payload|
path = payload[:layout]
- @layouts[path] += 1
+ if path
+ @layouts[path] += 1
+ if path =~ /^layouts\/(.*)/
+ @layouts[$1] += 1
+ end
+ end
end
ActiveSupport::Notifications.subscribe("!render_template.action_view") do |name, start, finish, id, payload|
@@ -56,6 +61,15 @@ module ActionController
# # assert that the "new" view template was rendered
# assert_template "new"
#
+ # # assert that the layout 'admin' was rendered
+ # assert_template :layout => 'admin'
+ # assert_template :layout => 'layouts/admin'
+ # assert_template :layout => :admin
+ #
+ # # assert that no layout was rendered
+ # assert_template :layout => nil
+ # assert_template :layout => false
+ #
# # assert that the "_customer" partial was rendered twice
# assert_template :partial => '_customer', :count => 2
#
@@ -88,17 +102,18 @@ module ActionController
end
end
when Hash
- if expected_layout = options[:layout]
+ if options.key?(:layout)
+ expected_layout = options[:layout]
msg = build_message(message,
"expecting layout <?> but action rendered <?>",
expected_layout, @layouts.keys)
case expected_layout
- when String
- assert(@layouts.keys.include?(expected_layout), msg)
+ when String, Symbol
+ assert(@layouts.keys.include?(expected_layout.to_s), msg)
when Regexp
assert(@layouts.keys.any? {|l| l =~ expected_layout }, msg)
- when nil
+ when nil, false
assert(@layouts.empty?, msg)
end
end
@@ -125,7 +140,7 @@ module ActionController
options[:partial], @partials.keys)
assert(@partials.include?(expected_partial), msg)
end
- else
+ elsif options.key?(:partial)
assert @partials.empty?,
"Expected no partials to be rendered"
end
@@ -460,7 +475,7 @@ module ActionController
parameters ||= {}
controller_class_name = @controller.class.anonymous? ?
"anonymous_controller" :
- @controller.class.name.underscore.sub(/_controller$/, '')
+ @controller.class.controller_path
@request.assign_parameters(@routes, controller_class_name, action.to_s, parameters)
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index d71b21efc3..bfa816798d 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -779,6 +779,10 @@ module ActionDispatch
child
end
+ def merge_action_scope(parent, child) #:nodoc:
+ child
+ end
+
def merge_path_names_scope(parent, child) #:nodoc:
merge_options_scope(parent, child)
end
@@ -1253,6 +1257,10 @@ module ActionDispatch
paths = [path] + rest
end
+ if @scope[:controller] && @scope[:action]
+ options[:to] ||= "#{@scope[:controller]}##{@scope[:action]}"
+ end
+
path_without_format = path.to_s.sub(/\(\.:format\)$/, '')
if using_match_shorthand?(path_without_format, options)
options[:to] ||= path_without_format.gsub(%r{^/}, "").sub(%r{/([^/]*)$}, '#\1')
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index a993699e05..6e63f92ff3 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -97,9 +97,7 @@ module ActionDispatch
@routes = {}
@helpers = []
- @module = Module.new do
- instance_methods.each { |selector| remove_method(selector) }
- end
+ @module = Module.new
end
def helper_names
@@ -108,13 +106,11 @@ module ActionDispatch
def clear!
@helpers.each do |helper|
- @module.module_eval do
- remove_possible_method helper
- end
+ @module.remove_possible_method helper
end
- @routes = {}
- @helpers = []
+ @routes.clear
+ @helpers.clear
end
def add(name, route)
diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb
index c192d3704e..636a37b699 100644
--- a/actionpack/lib/action_view/asset_paths.rb
+++ b/actionpack/lib/action_view/asset_paths.rb
@@ -43,7 +43,7 @@ module ActionView
end
def is_uri?(path)
- path =~ %r{^[-a-z]+://|^(?:cid|data):|^//}
+ path =~ %r{^[-a-z]+://|^(?:cid|data):|^//}i
end
private
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 99aa144d3a..39b9a8d27c 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -112,7 +112,7 @@ module ActionView
# english it would read better as about 80 years.
minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
remainder = (minutes_with_offset % 525600)
- distance_in_years = (minutes_with_offset / 525600)
+ distance_in_years = (minutes_with_offset.div 525600)
if remainder < 131400
locale.t(:about_x_years, :count => distance_in_years)
elsif remainder < 394200
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 920dc3f794..0c079256a3 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -1196,27 +1196,26 @@ module ActionView
def add_default_name_and_id(options)
if options.has_key?("index")
- options["name"] ||= tag_name_with_index(options["index"])
+ options["name"] ||= tag_name_with_index(options["index"], options["multiple"])
options["id"] = options.fetch("id"){ tag_id_with_index(options["index"]) }
options.delete("index")
elsif defined?(@auto_index)
- options["name"] ||= tag_name_with_index(@auto_index)
+ options["name"] ||= tag_name_with_index(@auto_index, options["multiple"])
options["id"] = options.fetch("id"){ tag_id_with_index(@auto_index) }
else
- options["name"] ||= tag_name
+ options["name"] ||= tag_name(options["multiple"])
options["id"] = options.fetch("id"){ tag_id }
end
- options["name"] += "[]" if options["multiple"] && !options["name"].ends_with?("[]")
options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence
end
- def tag_name
- "#{@object_name}[#{sanitized_method_name}]"
+ def tag_name(multiple = false)
+ "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
end
- def tag_name_with_index(index)
- "#{@object_name}[#{index}][#{sanitized_method_name}]"
+ def tag_name_with_index(index, multiple = false)
+ "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
end
def tag_id
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 812bb4de9e..51c3100dff 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -422,7 +422,7 @@ module ActionView
if block_given?
block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
else
- name
+ ERB::Util.html_escape(name)
end
else
link_to(name, options, html_options)
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 9f617a9a53..1a656ed37f 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -103,7 +103,7 @@ module ActionView
# Helpers related to template lookup using the lookup context information.
module ViewPaths
- attr_reader :view_paths
+ attr_reader :view_paths, :html_fallback_for_js
# Whenever setting view paths, makes a copy so we can manipulate then in
# instance objects as we wish.
@@ -200,7 +200,10 @@ module ActionView
def formats=(values)
if values
values.concat(default_formats) if values.delete "*/*"
- values << :html if values == [:js]
+ if values == [:js]
+ values << :html
+ @html_fallback_for_js = true
+ end
end
super(values)
end
diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb
index 0b5d3785d4..b79b89e142 100644
--- a/actionpack/lib/action_view/renderer/abstract_renderer.rb
+++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb
@@ -37,5 +37,11 @@ module ActionView
def instrument(name, options={})
ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield }
end
+
+ def prepend_formats(formats)
+ formats = Array(formats)
+ return if formats.empty? || @lookup_context.html_fallback_for_js
+ @lookup_context.formats = formats | @lookup_context.formats
+ end
end
end
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index 71fa05ab3e..f3300e470b 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -281,6 +281,8 @@ module ActionView
@block = block
@details = extract_details(options)
+ prepend_formats(options[:formats])
+
if String === partial
@object = options[:object]
@path = partial
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index a27d5dd1b1..d15e75637a 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -10,9 +10,10 @@ module ActionView
template = determine_template(options)
context = @lookup_context
+ prepend_formats(template.formats)
+
unless context.rendered_format
- context.formats = template.formats unless template.formats.empty?
- context.rendered_format = context.formats.first
+ context.rendered_format = template.formats.first || formats.last
end
render_template(template, options[:layout], options[:locals])
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 5252e43c25..3b5a515e84 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -76,6 +76,11 @@ class ActionPackAssertionsController < ActionController::Base
render "test/hello_world", :layout => "layouts/standard"
end
+ def render_with_layout_and_partial
+ @variable_for_layout = nil
+ render "test/hello_world_with_partial", :layout => "layouts/standard"
+ end
+
def session_stuffing
session['xmas'] = 'turkey'
render :text => "ho ho ho"
@@ -483,11 +488,43 @@ class AssertTemplateTest < ActionController::TestCase
end
end
+ def test_fails_expecting_no_layout
+ get :render_with_layout
+ assert_raise(ActiveSupport::TestCase::Assertion) do
+ assert_template :layout => nil
+ end
+ end
+
def test_passes_with_correct_layout
get :render_with_layout
assert_template :layout => "layouts/standard"
end
+ def test_passes_with_layout_and_partial
+ get :render_with_layout_and_partial
+ assert_template :layout => "layouts/standard"
+ end
+
+ def test_passed_with_no_layout
+ get :hello_world
+ assert_template :layout => nil
+ end
+
+ def test_passed_with_no_layout_false
+ get :hello_world
+ assert_template :layout => false
+ end
+
+ def test_passes_with_correct_layout_without_layouts_prefix
+ get :render_with_layout
+ assert_template :layout => "standard"
+ end
+
+ def test_passes_with_correct_layout_symbol
+ get :render_with_layout
+ assert_template :layout => :standard
+ end
+
def test_assert_template_reset_between_requests
get :hello_world
assert_template 'test/hello_world'
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 88a5c37c43..659c6c715e 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -529,6 +529,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
end
+
+ scope '/job', :controller => 'job' do
+ scope ':id', :action => 'manage_applicant' do
+ get "/active"
+ end
+ end
end
end
@@ -1444,6 +1450,13 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_controller_option_with_nesting_and_leading_slash
+ with_test_routes do
+ get '/job/5/active'
+ assert_equal 'job#manage_applicant', @response.body
+ end
+ end
+
def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper
with_test_routes do
assert_equal '/replies', replies_path
diff --git a/actionpack/test/fixtures/test/_changing_priority.html.erb b/actionpack/test/fixtures/test/_changing_priority.html.erb
new file mode 100644
index 0000000000..3225efc49a
--- /dev/null
+++ b/actionpack/test/fixtures/test/_changing_priority.html.erb
@@ -0,0 +1 @@
+HTML \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_changing_priority.json.erb b/actionpack/test/fixtures/test/_changing_priority.json.erb
new file mode 100644
index 0000000000..7fa41dce66
--- /dev/null
+++ b/actionpack/test/fixtures/test/_changing_priority.json.erb
@@ -0,0 +1 @@
+JSON \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_first_json_partial.json.erb b/actionpack/test/fixtures/test/_first_json_partial.json.erb
new file mode 100644
index 0000000000..790ee896db
--- /dev/null
+++ b/actionpack/test/fixtures/test/_first_json_partial.json.erb
@@ -0,0 +1 @@
+<%= render :partial => "test/second_json_partial" %> \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_json_change_priority.json.erb b/actionpack/test/fixtures/test/_json_change_priority.json.erb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/actionpack/test/fixtures/test/_json_change_priority.json.erb
diff --git a/actionpack/test/fixtures/test/_second_json_partial.json.erb b/actionpack/test/fixtures/test/_second_json_partial.json.erb
new file mode 100644
index 0000000000..5ebb7f1afd
--- /dev/null
+++ b/actionpack/test/fixtures/test/_second_json_partial.json.erb
@@ -0,0 +1 @@
+Third level \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/change_priority.html.erb b/actionpack/test/fixtures/test/change_priority.html.erb
new file mode 100644
index 0000000000..71ecef11c4
--- /dev/null
+++ b/actionpack/test/fixtures/test/change_priority.html.erb
@@ -0,0 +1,2 @@
+<%= render :partial => "test/json_change_priority", :formats => :json %>
+HTML Template, but <%= render :partial => "test/changing_priority" %> partial \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/hello_world_with_partial.html.erb b/actionpack/test/fixtures/test/hello_world_with_partial.html.erb
new file mode 100644
index 0000000000..ec31545356
--- /dev/null
+++ b/actionpack/test/fixtures/test/hello_world_with_partial.html.erb
@@ -0,0 +1,2 @@
+Hello world!
+<%= render '/test/partial' %>
diff --git a/actionpack/test/fixtures/test/html_template.html.erb b/actionpack/test/fixtures/test/html_template.html.erb
new file mode 100644
index 0000000000..1b483357bd
--- /dev/null
+++ b/actionpack/test/fixtures/test/html_template.html.erb
@@ -0,0 +1 @@
+<%= render :partial => "test/first_json_partial", :formats => :json %> \ No newline at end of file
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index b1a01b53b1..6b1bc01f54 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -79,13 +79,17 @@ class AssetTagHelperTest < ActionView::TestCase
JavascriptPathToTag = {
%(javascript_path("xmlhr")) => %(/javascripts/xmlhr.js),
%(javascript_path("super/xmlhr")) => %(/javascripts/super/xmlhr.js),
- %(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js)
+ %(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js),
+ %(javascript_path("http://www.outside.com/foo.js")) => %(http://www.outside.com/foo.js),
+ %(javascript_path("HTTP://www.outside.com/foo.js")) => %(HTTP://www.outside.com/foo.js)
}
PathToJavascriptToTag = {
%(path_to_javascript("xmlhr")) => %(/javascripts/xmlhr.js),
%(path_to_javascript("super/xmlhr")) => %(/javascripts/super/xmlhr.js),
- %(path_to_javascript("/super/xmlhr.js")) => %(/super/xmlhr.js)
+ %(path_to_javascript("/super/xmlhr.js")) => %(/super/xmlhr.js),
+ %(path_to_javascript("http://www.outside.com/foo.js")) => %(http://www.outside.com/foo.js),
+ %(path_to_javascript("HTTP://www.outside.com/foo.js")) => %(HTTP://www.outside.com/foo.js)
}
JavascriptIncludeToTag = {
@@ -109,14 +113,18 @@ class AssetTagHelperTest < ActionView::TestCase
%(stylesheet_path("bank")) => %(/stylesheets/bank.css),
%(stylesheet_path("bank.css")) => %(/stylesheets/bank.css),
%(stylesheet_path('subdir/subdir')) => %(/stylesheets/subdir/subdir.css),
- %(stylesheet_path('/subdir/subdir.css')) => %(/subdir/subdir.css)
+ %(stylesheet_path('/subdir/subdir.css')) => %(/subdir/subdir.css),
+ %(stylesheet_path("http://www.outside.com/foo.css")) => %(http://www.outside.com/foo.css),
+ %(stylesheet_path("HTTP://www.outside.com/foo.css")) => %(HTTP://www.outside.com/foo.css)
}
PathToStyleToTag = {
%(path_to_stylesheet("style")) => %(/stylesheets/style.css),
%(path_to_stylesheet("style.css")) => %(/stylesheets/style.css),
%(path_to_stylesheet('dir/file')) => %(/stylesheets/dir/file.css),
- %(path_to_stylesheet('/dir/file.rcss')) => %(/dir/file.rcss)
+ %(path_to_stylesheet('/dir/file.rcss')) => %(/dir/file.rcss),
+ %(path_to_stylesheet("http://www.outside.com/foo.css")) => %(http://www.outside.com/foo.css),
+ %(path_to_stylesheet("HTTP://www.outside.com/foo.css")) => %(HTTP://www.outside.com/foo.css)
}
StyleLinkToTag = {
@@ -139,14 +147,18 @@ class AssetTagHelperTest < ActionView::TestCase
%(image_path("xml")) => %(/images/xml),
%(image_path("xml.png")) => %(/images/xml.png),
%(image_path("dir/xml.png")) => %(/images/dir/xml.png),
- %(image_path("/dir/xml.png")) => %(/dir/xml.png)
+ %(image_path("/dir/xml.png")) => %(/dir/xml.png),
+ %(image_path("http://www.outside.com/foo.png")) => %(http://www.outside.com/foo.png),
+ %(image_path("HTTP://www.outside.com/foo.png")) => %(HTTP://www.outside.com/foo.png)
}
PathToImageToTag = {
%(path_to_image("xml")) => %(/images/xml),
%(path_to_image("xml.png")) => %(/images/xml.png),
%(path_to_image("dir/xml.png")) => %(/images/dir/xml.png),
- %(path_to_image("/dir/xml.png")) => %(/dir/xml.png)
+ %(path_to_image("/dir/xml.png")) => %(/dir/xml.png),
+ %(path_to_image("http://www.outside.com/foo.png")) => %(http://www.outside.com/foo.png),
+ %(path_to_image("HTTP://www.outside.com/foo.png")) => %(HTTP://www.outside.com/foo.png)
}
ImageLinkToTag = {
@@ -181,14 +193,18 @@ class AssetTagHelperTest < ActionView::TestCase
%(video_path("xml")) => %(/videos/xml),
%(video_path("xml.ogg")) => %(/videos/xml.ogg),
%(video_path("dir/xml.ogg")) => %(/videos/dir/xml.ogg),
- %(video_path("/dir/xml.ogg")) => %(/dir/xml.ogg)
+ %(video_path("/dir/xml.ogg")) => %(/dir/xml.ogg),
+ %(video_path("http://www.outside.com/foo.ogg")) => %(http://www.outside.com/foo.ogg),
+ %(video_path("HTTP://www.outside.com/foo.ogg")) => %(HTTP://www.outside.com/foo.ogg)
}
PathToVideoToTag = {
%(path_to_video("xml")) => %(/videos/xml),
%(path_to_video("xml.ogg")) => %(/videos/xml.ogg),
%(path_to_video("dir/xml.ogg")) => %(/videos/dir/xml.ogg),
- %(path_to_video("/dir/xml.ogg")) => %(/dir/xml.ogg)
+ %(path_to_video("/dir/xml.ogg")) => %(/dir/xml.ogg),
+ %(path_to_video("http://www.outside.com/foo.ogg")) => %(http://www.outside.com/foo.ogg),
+ %(path_to_video("HTTP://www.outside.com/foo.ogg")) => %(HTTP://www.outside.com/foo.ogg)
}
VideoLinkToTag = {
@@ -211,14 +227,18 @@ class AssetTagHelperTest < ActionView::TestCase
%(audio_path("xml")) => %(/audios/xml),
%(audio_path("xml.wav")) => %(/audios/xml.wav),
%(audio_path("dir/xml.wav")) => %(/audios/dir/xml.wav),
- %(audio_path("/dir/xml.wav")) => %(/dir/xml.wav)
+ %(audio_path("/dir/xml.wav")) => %(/dir/xml.wav),
+ %(audio_path("http://www.outside.com/foo.wav")) => %(http://www.outside.com/foo.wav),
+ %(audio_path("HTTP://www.outside.com/foo.wav")) => %(HTTP://www.outside.com/foo.wav)
}
PathToAudioToTag = {
%(path_to_audio("xml")) => %(/audios/xml),
%(path_to_audio("xml.wav")) => %(/audios/xml.wav),
%(path_to_audio("dir/xml.wav")) => %(/audios/dir/xml.wav),
- %(path_to_audio("/dir/xml.wav")) => %(/dir/xml.wav)
+ %(path_to_audio("/dir/xml.wav")) => %(/dir/xml.wav),
+ %(path_to_audio("http://www.outside.com/foo.wav")) => %(http://www.outside.com/foo.wav),
+ %(path_to_audio("HTTP://www.outside.com/foo.wav")) => %(HTTP://www.outside.com/foo.wav)
}
AudioLinkToTag = {
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index e4f84f8dd7..ad46ff4429 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -19,6 +19,8 @@ class DateHelperTest < ActionView::TestCase
end
def assert_distance_of_time_in_words(from, to=nil)
+ Fixnum.send(:private, :/) if RUBY_VERSION >= '1.9.3' # test we avoid Integer#/ (redefined by mathn)
+
to ||= from
# 0..1 with include_seconds
@@ -96,6 +98,8 @@ class DateHelperTest < ActionView::TestCase
# test to < from
assert_equal "about 4 hours", distance_of_time_in_words(from + 4.hours, to)
assert_equal "less than 20 seconds", distance_of_time_in_words(from + 19.seconds, to, true)
+ ensure
+ Fixnum.send(:public, :/) if RUBY_VERSION >= '1.9.3'
end
def test_distance_in_words
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 7b35424ec7..22af39add4 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -301,6 +301,16 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, file_field("user", "avatar")
end
+ def test_file_field_with_multiple_behavior
+ expected = '<input id="import_file" multiple="multiple" name="import[file][]" type="file" />'
+ assert_dom_equal expected, file_field("import", "file", :multiple => true)
+ end
+
+ def test_file_field_with_multiple_behavior_and_explicit_name
+ expected = '<input id="import_file" multiple="multiple" name="custom" type="file" />'
+ assert_dom_equal expected, file_field("import", "file", :multiple => true, :name => "custom")
+ end
+
def test_hidden_field
assert_dom_equal '<input id="post_title" name="post[title]" type="hidden" value="Hello World" />',
hidden_field("post", "title")
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index b907e3297b..72f494c811 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -54,6 +54,16 @@ module RenderTestCases
assert_equal "Hello world", @view.render(:template => "test/one", :formats => [:html])
end
+ def test_render_partial_implicitly_use_format_of_the_rendered_partial
+ @view.lookup_context.formats = [:html]
+ assert_equal "Third level", @view.render(:template => "test/html_template")
+ end
+
+ def test_render_partial_use_last_prepended_format_for_partials_with_the_same_names
+ @view.lookup_context.formats = [:html]
+ assert_equal "\nHTML Template, but JSON partial", @view.render(:template => "test/change_priority")
+ end
+
def test_render_template_with_a_missing_partial_of_another_format
@view.lookup_context.formats = [:html]
assert_raise ActionView::Template::Error, "Missing partial /missing with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder]}" do
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 38f77203e0..a00d71ff29 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -306,6 +306,11 @@ class UrlHelperTest < ActiveSupport::TestCase
link_to_unless(true, "Showing", url_hash) {
"test"
}
+
+ assert_equal %{&lt;b&gt;Showing&lt;/b&gt;}, link_to_unless(true, "<b>Showing</b>", url_hash)
+ assert_equal %{<a href="/">&lt;b&gt;Showing&lt;/b&gt;</a>}, link_to_unless(false, "<b>Showing</b>", url_hash)
+ assert_equal %{<b>Showing</b>}, link_to_unless(true, "<b>Showing</b>".html_safe, url_hash)
+ assert_equal %{<a href="/"><b>Showing</b></a>}, link_to_unless(false, "<b>Showing</b>".html_safe, url_hash)
end
def test_link_to_if
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index c0e0bb1dbc..c673a278f6 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,98 @@
## unreleased ##
+* Fix `ActiveRecord::Store` incorrectly tracking changes of its attributes.
+ Fixes #10373.
+
+ *Janko Marohnić*
+
+* Fix mysql2 adapter raises the correct exception when executing a query on a
+ closed connection.
+
+ *Yves Senn*
+
+* Fixes bug where `Company.new.contract_ids` would incorrectly load
+ all non-associated contracts.
+
+ Example:
+
+ company = Company.new # Company has many :contracts
+
+ # before
+ company.contract_ids # => SELECT ... WHERE `contracts`.`company_id` IS NULL
+
+ # after
+ company.contract_ids # => []
+
+ *Jared Armstrong*
+
+* Fix the `:primary_key` option for `has_many` associations.
+ Fixes #10693.
+
+ *Yves Senn*
+
+* fixes bug introduced by #3329. Now, when autosaving associations,
+ deletions happen before inserts and saves. This prevents a 'duplicate
+ unique value' database error that would occur if a record being created had
+ the same value on a unique indexed field as that of a record being destroyed.
+
+ Backport of #10417
+
+ *Johnny Holton*
+
+* Fix that under some conditions, Active Record could produce invalid SQL of the sort:
+ "SELECT DISTINCT DISTINCT".
+
+ Backport of #6792.
+
+ *Ben Woosley*
+
+* Require `ActiveRecord::Base` in railtie hooks for rake_tasks, console and runner to
+ avoid circular constant loading issues.
+
+ Backport #7695.
+
+ Fixes #7683 and #882
+
+ *Ben Holley*
+
+* Maintain context for joins within ActiveRecord::Relation merges.
+ Backport #10164.
+
+ *Neeraj Singh + Andrew Horner*
+
+* Make sure the `EXPLAIN` command is never triggered by a `select_db` call.
+
+ *Daniel Schierbeck*
+
+* Revert changes on `pluck` that was ignoring the select clause when the relation already
+ has one. This caused a regression since it changed the behavior in a stable release.
+
+ Fixes #9777.
+
+ *Rafael Mendonça França*
+
+* Confirm a record has not already been destroyed before decrementing counter cache.
+
+ *Ben Tucker*
+
+* Default values for PostgreSQL bigint types now get parsed and dumped to the
+ schema correctly.
+ Backport #10098.
+
+ *Erik Peterson*
+
+* Removed warning when `auto_explain_threshold_in_seconds` is set and the
+ connection adapter doesn't support explain.
+ This is causing a regression since the Active Record Railtie is trying to
+ connect to the development database in the application boot.
+
+ *Rafael Mendonça França*
+
+* Do not reset `inheritance_column` when it's set explicitly.
+ Backport of #5327.
+
+ *kennyj + Fred Wu*
+
* Fix a problem wrong exception is occured
when raising no translatable exception in PostgreSQL.
@@ -27,6 +120,11 @@
## Rails 3.2.13 (Mar 18, 2013) ##
+* Chaining multiple preloaded scopes will correctly preload all the scopes
+ at the same time.
+
+ *Chris Geihsler*
+
* Reverted 921a296a3390192a71abeec6d9a035cc6d1865c8, 'Quote numeric values
compared to string columns.' This caused several regressions.
diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb
index 1759a41d93..d78717704c 100644
--- a/activerecord/lib/active_record/associations/builder/belongs_to.rb
+++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb
@@ -34,7 +34,10 @@ module ActiveRecord::Associations::Builder
method_name = "belongs_to_counter_cache_before_destroy_for_#{name}"
mixin.redefine_method(method_name) do
record = send(name)
- record.class.decrement_counter(cache_column, record.id) unless record.nil?
+
+ if record && !self.destroyed?
+ record.class.decrement_counter(cache_column, record.id)
+ end
end
model.before_destroy(method_name)
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 65e882867e..baddb9852f 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -43,7 +43,7 @@ module ActiveRecord
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
def ids_reader
- if loaded? || options[:finder_sql]
+ if owner.new_record? || loaded? || options[:finder_sql]
load_target.map do |record|
record.send(reflection.association_primary_key)
end
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index 059e6c77bc..5296cb7282 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -89,8 +89,7 @@ module ActiveRecord
records.each { |r| r.destroy }
update_counter(-records.length) unless inverse_updates_counter_cache?
else
- keys = records.map { |r| r[reflection.association_primary_key] }
- scope = scoped.where(reflection.association_primary_key => keys)
+ scope = self.scoped.where(reflection.klass.primary_key => records)
if method == :delete_all
update_counter(-scope.delete_all)
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index cd366ac8b7..e3d8356f49 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -109,7 +109,7 @@ module ActiveRecord
case associations
when Symbol, String
reflection = parent.reflections[associations.to_s.intern] or
- raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
+ raise ConfigurationError, "Association named '#{ associations }' was not found on #{parent.active_record.name}; perhaps you misspelled it?"
unless join_association = find_join_association(reflection, parent)
@reflections << reflection
join_association = build_join_association(reflection, parent)
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index 03963ab060..becf1a3f62 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -55,7 +55,12 @@ module ActiveRecord
def find_parent_in(other_join_dependency)
other_join_dependency.join_parts.detect do |join_part|
- parent == join_part
+ case parent
+ when JoinBase
+ parent.active_record == join_part.active_record
+ else
+ parent == join_part
+ end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index 4cb7b56b57..e052b00403 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -56,8 +56,7 @@ module ActiveRecord
through_options[:include] = options[:include] || options[:source]
through_options[:conditions] = options[:conditions]
end
-
- through_options[:order] = options[:order]
+ through_options[:order] = options[:order] if options.has_key?(:order)
end
through_options
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index e1499fc3b0..3fc9d307bc 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -332,16 +332,16 @@ module ActiveRecord
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
begin
- records_to_destroy = []
+ if autosave
+ records_to_destroy = records.select(&:marked_for_destruction?)
+ records_to_destroy.each { |record| association.proxy.destroy(record) }
+ records -= records_to_destroy
+ end
records.each do |record|
- next if record.destroyed?
-
saved = true
- if autosave && record.marked_for_destruction?
- records_to_destroy << record
- elsif autosave != false && (@new_record_before_save || record.new_record?)
+ if autosave != false && (@new_record_before_save || record.new_record?)
if autosave
saved = association.insert_record(record, false)
else
@@ -353,19 +353,14 @@ module ActiveRecord
raise ActiveRecord::Rollback unless saved
end
-
- records_to_destroy.each do |record|
- association.proxy.destroy(record)
- end
rescue
records.each {|x| IdentityMap.remove(x) } if IdentityMap.enabled?
raise
end
-
end
# reconstruct the scope now that we know the owner's id
- association.send(:reset_scope) if association.respond_to?(:reset_scope)
+ association.reset_scope if association.respond_to?(:reset_scope)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 524a7d30fc..c690b982a1 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -204,9 +204,11 @@ module ActiveRecord
# Executes the SQL statement in the context of this connection.
def execute(sql, name = nil)
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
- # made since we established the connection
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
+ if @connection
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
+ # made since we established the connection
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
+ end
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index cbbb195458..04de08e876 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -142,7 +142,7 @@ module ActiveRecord
when NilClass
nil
# Numeric types
- when /\A\(?(-?\d+(\.\d*)?\)?)\z/
+ when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
$1
# Character types
when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
diff --git a/activerecord/lib/active_record/explain_subscriber.rb b/activerecord/lib/active_record/explain_subscriber.rb
index 859c8edfc5..1d861a57db 100644
--- a/activerecord/lib/active_record/explain_subscriber.rb
+++ b/activerecord/lib/active_record/explain_subscriber.rb
@@ -15,7 +15,7 @@ module ActiveRecord
# On the other hand, we want to monitor the performance of our real database
# queries, not the performance of the access to the query cache.
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE)
- EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)/i
+ EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)\b/i
def ignore_payload?(payload)
payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 1517e5ec17..e10e6b4aa8 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -173,6 +173,7 @@ module ActiveRecord
def inheritance_column=(value)
@original_inheritance_column = inheritance_column
@inheritance_column = value.to_s
+ @explicit_inheritance_column = true
end
def set_inheritance_column(value = nil, &block) #:nodoc:
@@ -300,7 +301,8 @@ module ActiveRecord
connection.schema_cache.clear_table_cache!(table_name) if table_exists?
@column_names = @content_columns = @column_defaults = @columns = @columns_hash = nil
- @dynamic_methods_hash = @inheritance_column = nil
+ @dynamic_methods_hash = nil
+ @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
@arel_engine = @relation = nil
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 05091654c0..41b62f6037 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -92,8 +92,9 @@ module ActiveRecord
# accepts_nested_attributes_for :posts
# end
#
- # You can now set or update attributes on an associated post model through
- # the attribute hash.
+ # You can now set or update attributes on the associated posts through
+ # an attribute hash for a member: include the key +:posts_attributes+
+ # with an array of hashes of post attributes as a value.
#
# For each hash that does _not_ have an <tt>id</tt> key a new record will
# be instantiated, unless the hash also contains a <tt>_destroy</tt> key
@@ -116,10 +117,10 @@ module ActiveRecord
# hashes if they fail to pass your criteria. For example, the previous
# example could be rewritten as:
#
- # class Member < ActiveRecord::Base
- # has_many :posts
- # accepts_nested_attributes_for :posts, :reject_if => proc { |attributes| attributes['title'].blank? }
- # end
+ # class Member < ActiveRecord::Base
+ # has_many :posts
+ # accepts_nested_attributes_for :posts, :reject_if => proc { |attributes| attributes['title'].blank? }
+ # end
#
# params = { :member => {
# :name => 'joe', :posts_attributes => [
@@ -136,19 +137,19 @@ module ActiveRecord
#
# Alternatively, :reject_if also accepts a symbol for using methods:
#
- # class Member < ActiveRecord::Base
- # has_many :posts
- # accepts_nested_attributes_for :posts, :reject_if => :new_record?
- # end
+ # class Member < ActiveRecord::Base
+ # has_many :posts
+ # accepts_nested_attributes_for :posts, :reject_if => :new_record?
+ # end
#
- # class Member < ActiveRecord::Base
- # has_many :posts
- # accepts_nested_attributes_for :posts, :reject_if => :reject_posts
+ # class Member < ActiveRecord::Base
+ # has_many :posts
+ # accepts_nested_attributes_for :posts, :reject_if => :reject_posts
#
- # def reject_posts(attributed)
- # attributed['title'].blank?
- # end
- # end
+ # def reject_posts(attributed)
+ # attributed['title'].blank?
+ # end
+ # end
#
# If the hash contains an <tt>id</tt> key that matches an already
# associated record, the matching record will be modified:
@@ -185,6 +186,29 @@ module ActiveRecord
# member.save
# member.reload.posts.length # => 1
#
+ # Nested attributes for an associated collection can also be passed in
+ # the form of a hash of hashes instead of an array of hashes:
+ #
+ # Member.create(:name => 'joe',
+ # :posts_attributes => { :first => { :title => 'Foo' },
+ # :second => { :title => 'Bar' } })
+ #
+ # has the same effect as
+ #
+ # Member.create(:name => 'joe',
+ # :posts_attributes => [ { :title => 'Foo' },
+ # { :title => 'Bar' } ])
+ #
+ # The keys of the hash which is the value for +:posts_attributes+ are
+ # ignored in this case.
+ # However, it is not allowed to use +'id'+ or +:id+ for one of
+ # such keys, otherwise the hash will be wrapped in an array and
+ # interpreted as an attribute hash for a single post.
+ #
+ # Passing attributes for an associated collection in the form of a hash
+ # of hashes can be used with hashes generated from HTTP/HTML parameters,
+ # where there maybe no natural way to submit an array of hashes.
+ #
# === Saving
#
# All changes to models, including the destruction of those marked for
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 055d27d85c..4e39654e5b 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -30,6 +30,7 @@ module ActiveRecord
)
rake_tasks do
+ require "active_record/base"
load "active_record/railties/databases.rake"
end
@@ -38,9 +39,14 @@ module ActiveRecord
# first time. Also, make it output to STDERR.
console do |app|
require "active_record/railties/console_sandbox" if app.sandbox?
+ require "active_record/base"
ActiveRecord::Base.logger = Logger.new(STDERR)
end
+ runner do |app|
+ require "active_record/base"
+ end
+
initializer "active_record.initialize_timezone" do
ActiveSupport.on_load(:active_record) do
self.time_zone_aware_attributes = true
@@ -83,13 +89,6 @@ module ActiveRecord
end
end
- initializer "active_record.validate_explain_support" do |app|
- if app.config.active_record[:auto_explain_threshold_in_seconds] &&
- !ActiveRecord::Base.connection.supports_explain?
- warn "auto_explain_threshold_in_seconds is set but will be ignored because your adapter does not support this feature. Please unset the configuration to avoid this warning."
- end
- end
-
# Expose database runtime to controller for logging.
initializer "active_record.log_runtime" do |app|
require "active_record/railties/controller_runtime"
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 1f9dbdc3d4..afab793a0c 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -179,14 +179,13 @@ module ActiveRecord
def pluck(column_name)
if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
column_name = "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
- else
- column_name = column_name.to_s
end
- relation = clone
- relation.select_values = [column_name]
- klass.connection.select_all(relation.arel).map! do |attributes|
- klass.type_cast_attribute(attributes.keys.first, klass.initialize_attributes(attributes))
+ result = klass.connection.exec_query(select(column_name).to_sql)
+ last_column = result.columns.last
+
+ result.map do |attributes|
+ klass.type_cast_attribute(last_column, klass.initialize_attributes(attributes))
end
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 08cfe4f70d..cdf18f8080 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -254,6 +254,7 @@ module ActiveRecord
values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders)
relation = relation.dup.select(values)
+ relation.uniq_value = nil
id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
ids_array = id_rows.map {|row| row[primary_key]}
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index c25570d758..90f2ac3cde 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -17,17 +17,17 @@ module ActiveRecord
if method == :includes
merged_relation = merged_relation.includes(value)
else
- merged_relation.send(:"#{method}_values=", value)
+ merge_relation_method(merged_relation, method, value)
end
end
end
(Relation::MULTI_VALUE_METHODS - [:joins, :where, :order]).each do |method|
value = r.send(:"#{method}_values")
- merged_relation.send(:"#{method}_values=", merged_relation.send(:"#{method}_values") + value) if value.present?
+ merge_relation_method(merged_relation, method, value) if value.present?
end
- merged_relation.joins_values += r.joins_values
+ merge_joins(merged_relation, r)
merged_wheres = @where_values + r.where_values
@@ -144,5 +144,36 @@ module ActiveRecord
relation
end
+ private
+
+ def merge_joins(relation, other)
+ values = other.joins_values
+ return if values.blank?
+
+ if other.klass == relation.klass
+ relation.joins_values += values
+ else
+ joins_dependency, rest = values.partition do |join|
+ case join
+ when Hash, Symbol, Array
+ true
+ else
+ false
+ end
+ end
+
+ join_dependency = ActiveRecord::Associations::JoinDependency.new(
+ other.klass,
+ joins_dependency,
+ []
+ )
+
+ relation.joins_values += join_dependency.join_associations + rest
+ end
+ end
+
+ def merge_relation_method(relation, method, value)
+ relation.send(:"#{method}_values=", relation.send(:"#{method}_values") + value)
+ end
end
end
diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb
index 49d01de365..bacb78e2e1 100644
--- a/activerecord/lib/active_record/store.rb
+++ b/activerecord/lib/active_record/store.rb
@@ -37,8 +37,8 @@ module ActiveRecord
Array(keys).flatten.each do |key|
define_method("#{key}=") do |value|
send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash)
- send(store_attribute)[key] = value
send("#{store_attribute}_will_change!")
+ send(store_attribute)[key] = value
end
define_method(key) do
diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
new file mode 100644
index 0000000000..5ed2d8aba2
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
@@ -0,0 +1,46 @@
+# encoding: utf-8
+
+require "cases/helper"
+require 'active_record/base'
+require 'active_record/connection_adapters/postgresql_adapter'
+
+class PostgresqlByteaTest < ActiveRecord::TestCase
+ class ByteaDataType < ActiveRecord::Base
+ self.table_name = 'bytea_data_type'
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ begin
+ @connection.transaction do
+ @connection.create_table('bytea_data_type') do |t|
+ t.binary 'payload'
+ t.binary 'serialized'
+ end
+ end
+ end
+ @column = ByteaDataType.columns.find { |c| c.name == 'payload' }
+ assert(@column.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn))
+ end
+
+ def teardown
+ @connection.execute 'drop table if exists bytea_data_type'
+ end
+
+ class Serializer
+ def load(str); str; end
+ def dump(str); str; end
+ end
+
+ def test_serialize
+ serializer = Serializer.new
+ klass = Class.new(ByteaDataType) {
+ serialize :serialized, Serializer.new
+ }
+ obj = klass.new
+ obj.serialized = "hello world"
+ obj.save!
+ obj.reload
+ assert_equal "hello world", obj.serialized
+ end
+end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index c9b26895ae..58c788e42d 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -387,6 +387,26 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal 15, topic.replies.size
end
+ def test_counter_cache_double_destroy
+ topic = Topic.create :title => "Zoom-zoom-zoom"
+
+ 5.times do
+ topic.replies.create(:title => "re: zoom", :content => "speedy quick!")
+ end
+
+ assert_equal 5, topic.reload[:replies_count]
+ assert_equal 5, topic.replies.size
+
+ reply = topic.replies.first
+
+ reply.destroy
+ assert_equal 4, topic.reload[:replies_count]
+
+ reply.destroy
+ assert_equal 4, topic.reload[:replies_count]
+ assert_equal 4, topic.replies.size
+ end
+
def test_custom_counter_cache
reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
assert_equal 0, reply[:replies_count]
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 944f135153..42061d3d73 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -1118,4 +1118,11 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_no_queries { assert_equal 2, author.comments_with_order_and_conditions.size }
assert_no_queries { assert_equal 5, author.posts.size, "should not cache a subset of the association" }
end
+
+ test "preloading a through association twice does not reset it" do
+ members = Member.includes(:current_membership => :club).includes(:club).to_a
+ assert_no_queries {
+ assert_equal 3, members.map(&:current_membership).map(&:club).size
+ }
+ 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 869ec1e4b8..d94f5d3207 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -1311,6 +1311,33 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert !company.clients.loaded?
end
+ def test_get_ids_for_association_on_new_record_does_not_try_to_find_records
+ Company.columns # Load schema information so we don't query below
+ Contract.columns # if running just this test.
+
+ company = Company.new
+ assert_queries(0) do
+ company.contract_ids
+ end
+
+ assert_equal [], company.contract_ids
+ end
+
+ def test_set_ids_for_association_on_new_record_applies_association_correctly
+ contract_a = Contract.create!
+ contract_b = Contract.create!
+ Contract.create! # another contract
+ company = Company.new(:name => "Some Company")
+
+ company.contract_ids = [contract_a.id, contract_b.id]
+ assert_equal [contract_a.id, contract_b.id], company.contract_ids
+ assert_equal [contract_a, contract_b], company.contracts
+
+ company.save!
+ assert_equal company, contract_a.reload.company
+ assert_equal company, contract_b.reload.company
+ end
+
def test_get_ids_ignores_include_option
assert_equal [readers(:michael_welcome).id], posts(:welcome).readers_with_person_ids
end
@@ -1492,6 +1519,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal david.essays, Essay.find_all_by_writer_id("David")
end
+ def test_has_many_assignment_with_custom_primary_key
+ david = people(:david)
+
+ assert_equal ["A Modest Proposal"], david.essays.map(&:name)
+ david.essays = [Essay.create!(:name => "Remote Work" )]
+ assert_equal ["Remote Work"], david.essays.map(&:name)
+ end
+
def test_blank_custom_primary_key_on_new_record_should_not_run_queries
author = Author.new
assert !author.essays.loaded?
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index bba1b2b66d..656798300d 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -596,7 +596,7 @@ class TestDefaultAutosaveAssociationOnNewRecord < ActiveRecord::TestCase
end
class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
- self.use_transactional_fixtures = false unless supports_savepoints?
+ self.use_transactional_fixtures = false
def setup
@pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?")
@@ -793,6 +793,20 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
assert_equal 2, @pirate.birds.reload.length
end
+ def test_should_save_new_record_that_has_same_value_as_existing_record_marked_for_destruction_on_field_that_has_unique_index
+ Bird.connection.add_index :birds, :name, :unique => true
+
+ 3.times { |i| @pirate.birds.create(:name => "unique_birds_#{i}") }
+
+ @pirate.birds[0].mark_for_destruction
+ @pirate.birds.build(:name => @pirate.birds[0].name)
+ @pirate.save!
+
+ assert_equal 3, @pirate.birds.reload.length
+ ensure
+ Bird.connection.remove_index :birds, :column => :name
+ end
+
# Add and remove callbacks tests for association collections.
%w{ method proc }.each do |callback_type|
define_method("test_should_run_add_callback_#{callback_type}s_for_has_many") do
@@ -875,8 +889,10 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
@pirate.parrots.each { |parrot| parrot.mark_for_destruction }
assert @pirate.save
- assert_queries(0) do
- assert @pirate.save
+ Pirate.transaction do
+ assert_queries(0) do
+ assert @pirate.save
+ end
end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 97d6c0cf88..67b5d174aa 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1540,6 +1540,16 @@ class BasicsTest < ActiveRecord::TestCase
end
end
+ def test_dont_clear_inheritnce_column_when_setting_explicitly
+ Joke.inheritance_column = "my_type"
+ before_inherit = Joke.inheritance_column
+
+ Joke.reset_column_information
+ after_inherit = Joke.inheritance_column
+
+ assert_equal before_inherit, after_inherit unless before_inherit.blank? && after_inherit.blank?
+ end
+
def test_set_table_name_symbol_converted_to_string
Joke.table_name = :cold_jokes
assert_equal 'cold_jokes', Joke.table_name
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index a1dc1de38d..8755e1f580 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -493,10 +493,10 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [1,2,3,4], Topic.order(:id).pluck("topics.id")
end
- def test_pluck_replaces_select_clause
- taks_relation = Topic.select([:approved, :id]).order(:id)
- assert_equal [1,2,3,4], taks_relation.pluck(:id)
- assert_equal [false, true, true, true], taks_relation.pluck(:approved)
+ def test_pluck_does_not_replace_select_clause
+ taks_relation = Topic.select("approved, id, id AS foo_id").order('foo_id DESC')
+ assert_equal [4,3,2,1], taks_relation.pluck(:id)
+ assert_equal [true, true, true, false], taks_relation.pluck(:approved)
end
def test_pluck_auto_table_name_prefix
diff --git a/activerecord/test/cases/disconnected_test.rb b/activerecord/test/cases/disconnected_test.rb
new file mode 100644
index 0000000000..cc2c1f6489
--- /dev/null
+++ b/activerecord/test/cases/disconnected_test.rb
@@ -0,0 +1,26 @@
+require "cases/helper"
+
+class TestRecord < ActiveRecord::Base
+end
+
+class TestDisconnectedAdapter < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def teardown
+ spec = ActiveRecord::Base.connection_config
+ ActiveRecord::Base.establish_connection(spec)
+ @connection = nil
+ end
+
+ test "can't execute statements while disconnected" do
+ @connection.execute "SELECT count(*) from products"
+ @connection.disconnect!
+ assert_raises(ActiveRecord::StatementInvalid) do
+ @connection.execute "SELECT count(*) from products"
+ end
+ end
+end
diff --git a/activerecord/test/cases/explain_subscriber_test.rb b/activerecord/test/cases/explain_subscriber_test.rb
index 7b852a625d..0546e793fe 100644
--- a/activerecord/test/cases/explain_subscriber_test.rb
+++ b/activerecord/test/cases/explain_subscriber_test.rb
@@ -38,6 +38,13 @@ if ActiveRecord::Base.connection.supports_explain?
end
end
+ def test_collects_nothing_if_the_statement_is_only_partially_matched
+ with_queries([]) do |queries|
+ SUBSCRIBER.call(:name => 'SQL', :sql => 'select_db yo_mama')
+ assert queries.empty?
+ end
+ end
+
def test_collects_nothing_if_unexplained_sqls
with_queries([]) do |queries|
SUBSCRIBER.call(:name => 'SQL', :sql => 'SHOW max_identifier_length')
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 7d63d76c34..2efafe5c24 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -31,6 +31,13 @@ class FinderTest < ActiveRecord::TestCase
assert_equal(topics(:first).title, Topic.find(1).title)
end
+ def test_symbols_table_ref
+ Post.first # warm up
+ x = Symbol.all_symbols.count
+ Post.where("title" => {"xxxqqqq" => "bar"})
+ assert_equal x, Symbol.all_symbols.count
+ end
+
# find should handle strings that come from URLs
# (example: Category.find(params[:id]))
def test_find_with_string
@@ -86,6 +93,18 @@ class FinderTest < ActiveRecord::TestCase
assert !Topic.includes(:replies).limit(1).where('0 = 1').exists?
end
+ def test_exists_with_distinct_association_includes_and_limit
+ author = Author.first
+ assert !author.unique_categorized_posts.includes(:special_comments).limit(0).exists?
+ assert author.unique_categorized_posts.includes(:special_comments).limit(1).exists?
+ end
+
+ def test_exists_with_distinct_association_includes_limit_and_order
+ author = Author.first
+ assert !author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(0).exists?
+ assert author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(1).exists?
+ end
+
def test_exists_with_empty_table_and_no_args_given
Topic.delete_all
assert !Topic.exists?
diff --git a/activerecord/test/cases/mass_assignment_security_test.rb b/activerecord/test/cases/mass_assignment_security_test.rb
index 5153945546..13f90e8eef 100644
--- a/activerecord/test/cases/mass_assignment_security_test.rb
+++ b/activerecord/test/cases/mass_assignment_security_test.rb
@@ -300,6 +300,16 @@ class MassAssignmentSecurityTest < ActiveRecord::TestCase
assert_admin_attributes(p, true)
end
+ def test_attr_protected_with_newline
+ p = LoosePerson.new
+ assert_raises(ActiveRecord::UnknownAttributeError) do
+ p.attributes = {"comments=\n"=>"hax"}
+ end
+ assert_nil p.comments, "Comments is meant to be attr_protected but I assigned it with attributes="
+ p.attributes= {"comments(1)\n" => "hax"}
+ assert_nil p.comments, "Comments is meant to be attr_protected but I assigned it with attributes="
+ end
+
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index ada4294401..f14eee2eb8 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -4,6 +4,7 @@ require 'models/tagging'
require 'models/post'
require 'models/topic'
require 'models/comment'
+require 'models/rating'
require 'models/reply'
require 'models/author'
require 'models/comment'
@@ -19,7 +20,7 @@ require 'models/minivan'
class RelationTest < ActiveRecord::TestCase
fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments,
- :tags, :taggings, :cars, :minivans
+ :ratings, :tags, :taggings, :cars, :minivans
def test_do_not_double_quote_string_id
van = Minivan.last
@@ -332,6 +333,13 @@ class RelationTest < ActiveRecord::TestCase
end
end
+ def test_preload_applies_to_all_chained_preloaded_scopes
+ assert_queries(3) do
+ post = Post.with_tags.with_comments.first
+ assert post
+ end
+ end
+
def test_find_with_included_associations
assert_queries(2) do
posts = Post.includes(:comments).order('posts.id')
@@ -689,6 +697,12 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 1, comments.count
end
+ def test_relation_merging_with_merged_joins
+ special_comments_with_ratings = SpecialComment.joins(:ratings)
+ posts_with_special_comments_with_ratings = Post.group('posts.id').joins(:special_comments).merge(special_comments_with_ratings)
+ assert_equal 1, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length
+ end
+
def test_count
posts = Post.scoped
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 0a9643b7e0..629e5e0fff 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -206,6 +206,11 @@ class SchemaDumperTest < ActiveRecord::TestCase
end
if current_adapter?(:PostgreSQLAdapter)
+ def test_schema_dump_includes_bigint_default
+ output = standard_dump
+ assert_match %r{t.integer\s+"bigint_default",\s+:limit => 8,\s+:default => 0}, output
+ end
+
def test_schema_dump_includes_xml_shorthand_definition
output = standard_dump
if %r{create_table "postgresql_xml_data_type"} =~ output
diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb
index 277fc9d676..bbcbeac959 100644
--- a/activerecord/test/cases/store_test.rb
+++ b/activerecord/test/cases/store_test.rb
@@ -40,4 +40,11 @@ class StoreTest < ActiveRecord::TestCase
@john.remember_login = false
assert_equal false, @john.remember_login
end
+
+ test "updating the store will track changes correctly" do
+ @john.color = "blue"
+ assert_equal [{:color => "black"}, {:color => "blue"}], @john.settings_change
+ @john.homepage = "37signals.com"
+ assert_equal [{:color => "black"}, {:color => "blue", :homepage => "37signals.com"}], @john.settings_change
+ end
end
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index 07c529d685..d316a0b992 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -27,6 +27,7 @@ class Person < ActiveRecord::Base
has_many :agents_posts, :through => :agents, :source => :posts
has_many :agents_posts_authors, :through => :agents_posts, :source => :author
+ has_many :essays, :primary_key => "first_name", :foreign_key => "writer_id"
scope :males, :conditions => { :gender => 'M' }
scope :females, :conditions => { :gender => 'F' }
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 9aa02fa18f..3cfd1a0f76 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -76,6 +76,9 @@ class Post < ActiveRecord::Base
end
end
+ scope :with_comments, preload(:comments)
+ scope :with_tags, preload(:taggings)
+
has_many :interpolated_taggings, :class_name => 'Tagging', :as => :taggable, :conditions => proc { "1 = #{1}" }
has_many :interpolated_tags, :through => :taggings
has_many :interpolated_tags_2, :through => :interpolated_taggings, :source => :tag
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index b2c655ddcd..4f546df2eb 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -30,6 +30,7 @@ ActiveRecord::Schema.define do
char3 text default 'a text field',
positive_integer integer default 1,
negative_integer integer default -1,
+ bigint_default bigint default 0::bigint,
decimal_number decimal(3,2) default 2.78,
multiline_default text DEFAULT '--- []
diff --git a/activeresource/CHANGELOG.md b/activeresource/CHANGELOG.md
index 77419bb904..1d084ec5d9 100644
--- a/activeresource/CHANGELOG.md
+++ b/activeresource/CHANGELOG.md
@@ -1,7 +1,9 @@
## unreleased ##
-* No changes.
+* Fixes an issue that ActiveResource models ignores ActiveResource::Base.include_root_in_json.
+ Backported from the now separate repo rails/activeresouce.
+ *Xinjiang Lu*
## Rails 3.2.13 (Mar 18, 2013) ##
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 032a245c3c..f9cc7d03c8 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -1336,7 +1336,7 @@ module ActiveResource
end
def to_json(options={})
- super({ :root => self.class.element_name }.merge(options))
+ super(include_root_in_json ? { :root => self.class.element_name }.merge(options) : options)
end
def to_xml(options={})
diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb
index 983f0541a8..9176b5db93 100644
--- a/activeresource/test/cases/base_test.rb
+++ b/activeresource/test/cases/base_test.rb
@@ -1020,7 +1020,6 @@ class BaseTest < Test::Unit::TestCase
end
def test_to_json
- Person.include_root_in_json = true
joe = Person.find(6)
encode = joe.encode
json = joe.to_json
@@ -1032,6 +1031,21 @@ class BaseTest < Test::Unit::TestCase
assert_match %r{\}\}$}, json
end
+ def test_to_json_without_root
+ ActiveResource::Base.include_root_in_json = false
+ joe = Person.find(6)
+ encode = joe.encode
+ json = joe.to_json
+
+ assert_equal encode, json
+ assert_no_match %r{^\{"person":\}}, json
+ assert_match %r{"id":6}, json
+ assert_match %r{"name":"Joe"}, json
+ assert_match %r{\}$}, json
+ ensure
+ ActiveResource::Base.include_root_in_json = true
+ end
+
def test_to_json_with_element_name
old_elem_name = Person.element_name
Person.include_root_in_json = true
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 649766cc9b..d612c644af 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,16 @@
## unreleased ##
+* Override `Time.at` to support the passing of Time-like values when called with a single argument.
+
+ *Andrew White*
+
+* Revert the changes on unicode character encoding from `ActiveSupport::JSON.encode`.
+ This was causing a regression where the resulting string is always returning UTF-8.
+ Also it changes the behavior of this method on a stable release.
+ Fixes #9498.
+
+ *Rafael Mendonça França*
+
* Fix `ActiveSupport::TimeZone.parse` when time is at a local DST jump.
Fixes #9678.
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 9146d82bd8..7524063efb 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -45,6 +45,18 @@ class Time
def current
::Time.zone ? ::Time.zone.now : ::Time.now
end
+
+ # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
+ # instances can be used when called with a single argument
+ def at_with_coercion(*args)
+ if args.size == 1 && args.first.acts_like?(:time)
+ at_without_coercion(args.first.to_i)
+ else
+ at_without_coercion(*args)
+ end
+ end
+ alias_method :at_without_coercion, :at
+ alias_method :at, :at_with_coercion
end
# Tells whether the Time object's time lies in the past
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index a50e6524c6..bd2f909ca9 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -122,7 +122,13 @@ module ActiveSupport
if string.respond_to?(:force_encoding)
string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
end
- json = string.gsub(escape_regex) { |s| ESCAPED_CHARS[s] }
+ json = string.
+ gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
+ gsub(/([\xC0-\xDF][\x80-\xBF]|
+ [\xE0-\xEF][\x80-\xBF]{2}|
+ [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
+ s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
+ }
json = %("#{json}")
json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
json
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 0d680832ef..a22e161279 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -774,6 +774,28 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] ))
end
+ def test_at_with_datetime
+ assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(DateTime.civil(2000, 1, 1, 0, 0, 0))
+
+ # Only test this if the underlying Time.at raises a TypeError
+ begin
+ Time.at_without_coercion(Time.now, 0)
+ rescue TypeError
+ assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(DateTime.civil(2000, 1, 1, 0, 0, 0), 0)) }
+ end
+ end
+
+ def test_at_with_time_with_zone
+ assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC']))
+
+ # Only test this if the underlying Time.at raises a TypeError
+ begin
+ Time.at_without_coercion(Time.now, 0)
+ rescue TypeError
+ assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC']), 0)) }
+ end
+ end
+
def test_eql?
assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) )
assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) )
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index e4e13c3f25..72366f9ab4 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -100,11 +100,11 @@ class TestJSONEncoding < Test::Unit::TestCase
def test_utf8_string_encoded_properly_when_kcode_is_utf8
with_kcode 'UTF8' do
result = ActiveSupport::JSON.encode('€2.99')
- assert_equal '"€2.99"', result
+ assert_equal '"\\u20ac2.99"', result
assert_equal(Encoding::UTF_8, result.encoding) if result.respond_to?(:encoding)
result = ActiveSupport::JSON.encode('✎☺')
- assert_equal '"✎☺"', result
+ assert_equal '"\\u270e\\u263a"', result
assert_equal(Encoding::UTF_8, result.encoding) if result.respond_to?(:encoding)
end
end
@@ -113,22 +113,23 @@ class TestJSONEncoding < Test::Unit::TestCase
def test_non_utf8_string_transcodes
s = '二'.encode('Shift_JIS')
result = ActiveSupport::JSON.encode(s)
- assert_equal '"二"', result
+ assert_equal '"\\u4e8c"', result
assert_equal Encoding::UTF_8, result.encoding
end
- end
- def test_wide_utf8_chars
- w = '𠜎'
- result = ActiveSupport::JSON.encode(w)
- assert_equal '"𠜎"', result
- end
+ def test_utf8_hash_key_does_not_change_the_encoding
+ w = { '𠜎' => 'a' }
+ result = ActiveSupport::JSON.encode(w)
+ assert_equal '{"\\u070e":"a"}', result
- def test_wide_utf8_roundtrip
- hash = { :string => "𐒑" }
- json = ActiveSupport::JSON.encode(hash)
- decoded_hash = ActiveSupport::JSON.decode(json)
- assert_equal "𐒑", decoded_hash['string']
+ if RUBY_VERSION >= '2.0'
+ expected_encoding = Encoding::UTF_8
+ else
+ expected_encoding = Encoding::US_ASCII
+ end
+
+ assert_equal expected_encoding, result.encoding
+ end
end
def test_exception_raised_when_encoding_circular_reference_in_array
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index c0ab4b8317..4bb2ec4618 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,6 +1,15 @@
## unreleased ##
-* No changes.
+* Add support for runner hook.
+
+ Backport #7695.
+
+ *Ben Holley*
+
+* Fixes bug with scaffold generator with `--assets=false --resource-route=false`.
+ Fixes #9525.
+
+ *Arun Agrawal*
## Rails 3.2.13 (Mar 18, 2013) ##
diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile
index c2ca5a335d..444215f0fa 100644
--- a/railties/guides/source/caching_with_rails.textile
+++ b/railties/guides/source/caching_with_rails.textile
@@ -301,8 +301,6 @@ config.cache_store = :memory_store, :size => 64.megabytes
If you're running multiple Ruby on Rails server processes (which is the case if you're using mongrel_cluster or Phusion Passenger), then your Rails server process instances won't be able to share cache data with each other. This cache store is not appropriate for large application deployments, but can work well for small, low traffic sites with only a couple of server processes or for development and test environments.
-This is the default cache store implementation.
-
h4. ActiveSupport::Cache::FileStore
This cache store uses the file system to store entries. The path to the directory where the store files will be stored must be specified when initializing the cache.
@@ -315,6 +313,8 @@ With this cache store, multiple server processes on the same host can share a ca
Note that the cache will grow until the disk is full unless you periodically clear out old entries.
+This is the default cache store if config.cache_store is not defined and tmp/cache is writable.
+
h4. ActiveSupport::Cache::MemCacheStore
This cache store uses Danga's +memcached+ server to provide a centralized cache for your application. Rails uses the bundled +memcache-client+ gem by default. This is currently the most popular cache store for production websites. It can be used to provide a single, shared cache cluster with very a high performance and redundancy.
@@ -434,4 +434,4 @@ end
h3. Further reading
-* "Scaling Rails Screencasts":http://railslab.newrelic.com/scaling-rails
+* "Scaling Rails Screencasts":https://www.youtube.com/playlist?list=PLuVcDOUVjW2ePvFapFSHBZ71ya2fLHZS5
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index c32a23c50b..99409edbd0 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -1153,6 +1153,7 @@ First, take a look at +comment.rb+:
<ruby>
class Comment < ActiveRecord::Base
+ attr_accesssible :body, :commenter, :post
belongs_to :post
end
</ruby>
@@ -1215,6 +1216,7 @@ makes each comment belong to a Post:
<ruby>
class Comment < ActiveRecord::Base
+ attr_accessible :body, :commenter, :post
belongs_to :post
end
</ruby>
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index 5ae9cf0f2b..7d768fca19 100644
--- a/railties/guides/source/initialization.textile
+++ b/railties/guides/source/initialization.textile
@@ -383,7 +383,7 @@ ensure
end
</ruby>
-This is where the first output of the Rails initialization happens. This method creates a trap for +INT+ signals, so if you +CTRL+C+ the server, it will exit the process. As we can see from the code here, it will create the +tmp/cache+, +tmp/pids+, +tmp/sessions+ and +tmp/sockets+ directories if they don't already exist prior to calling +super+. The +super+ method will call +Rack::Server.start+ which begins its definition like this:
+This is where the first output of the Rails initialization happens. This method creates a trap for +INT+ signals, so if you <tt>CTRL+C</tt> the server, it will exit the process. As we can see from the code here, it will create the +tmp/cache+, +tmp/pids+, +tmp/sessions+ and +tmp/sockets+ directories if they don't already exist prior to calling +super+. The +super+ method will call +Rack::Server.start+ which begins its definition like this:
<ruby>
def start
diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb
index 35b6fc7014..4f4cedbd32 100644
--- a/railties/guides/source/layout.html.erb
+++ b/railties/guides/source/layout.html.erb
@@ -81,11 +81,11 @@
</p>
<p>
If you see any typos or factual errors you are confident to
- patch, please clone <%= link_to 'docrails', 'https://github.com/lifo/docrails' %>
- and push the change yourself. That branch of Rails has public write access.
- Commits are still reviewed, but that happens after you've submitted your
- contribution. <%= link_to 'docrails', 'https://github.com/lifo/docrails' %> is
- cross-merged with master periodically.
+ patch, please clone the <%= link_to 'rails', 'https://github.com/rails/rails' %>
+ repository and open a new pull request. You can also ask for commit rights on
+ <%= link_to 'docrails', 'https://github.com/rails/docrails' %> if you plan to submit
+ several patches. Commits are reviewed, but that happens after you've submitted your
+ contribution. This repository is cross-merged with master periodically.
</p>
<p>
You may also find incomplete content, or stuff that is not up to date.
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 4f695159ea..2281b9686c 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -154,6 +154,14 @@ module Rails
self
end
+ # Load the application runner and invoke the registered hooks.
+ # Check <tt>Rails::Railtie.runner</tt> for more info.
+ def load_runner(app=self)
+ initialize_runner
+ super
+ self
+ end
+
# Rails.application.env_config stores some of the Rails initial environment parameters.
# Currently stores:
#
@@ -305,6 +313,9 @@ module Rails
require "rails/console/helpers"
end
+ def initialize_runner #:nodoc:
+ end
+
def build_original_fullpath(env)
path_info = env["PATH_INFO"]
query_string = env["QUERY_STRING"]
diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb
index e8cc5d9e3b..a694218695 100644
--- a/railties/lib/rails/commands/runner.rb
+++ b/railties/lib/rails/commands/runner.rb
@@ -42,6 +42,7 @@ ENV["RAILS_ENV"] = options[:environment]
require APP_PATH
Rails.application.require_environment!
+ Rails.application.load_runner
if code_or_file.nil?
$stderr.puts "Run '#{$0} -h' for help."
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 993dfe43ee..77f335e45f 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -430,6 +430,11 @@ module Rails
super
end
+ def load_runner(app=self)
+ railties.all { |r| r.load_runner(app) }
+ super
+ end
+
def eager_load!
railties.all(&:eager_load!)
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
index f4efd3af74..8f8ebbbc1d 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
@@ -1,4 +1,4 @@
-source "http://rubygems.org"
+source "https://rubygems.org"
# Declare your gem's dependencies in <%= name %>.gemspec.
# Bundler will treat runtime dependencies like base dependencies, and
diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
index 03a61a035e..353ebe93ed 100644
--- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
@@ -8,6 +8,8 @@ module Rails
class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets"
class_option :stylesheet_engine, :desc => "Engine for Stylesheets"
+ class_option :assets, :type => :boolean
+ class_option :resource_route, :type => :boolean
hook_for :scaffold_controller, :required => true
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 07a122e7d0..9eb7e7c65d 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -145,6 +145,12 @@ module Rails
@load_console
end
+ def runner(&blk)
+ @load_runner ||= []
+ @load_runner << blk if blk
+ @load_runner
+ end
+
def generators(&blk)
@generators ||= []
@generators << blk if blk
@@ -179,6 +185,10 @@ module Rails
self.class.console.each { |block| block.call(app) }
end
+ def load_runner(app=self)
+ self.class.runner.each { |block| block.call(app) }
+ end
+
def load_tasks(app=self)
extend Rake::DSL if defined? Rake::DSL
self.class.rake_tasks.each { |block| self.instance_exec(app, &block) }
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index 107b54c0be..767a60f097 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -174,5 +174,27 @@ module ApplicationTests
end
end
end
+
+ def test_load_activerecord_base_when_we_use_observers
+ Dir.chdir(app_path) do
+ `bundle exec rails g model user;
+ bundle exec rake db:migrate;
+ bundle exec rails g observer user;`
+
+ add_to_config "config.active_record.observers = :user_observer"
+
+ assert_equal "0", `bundle exec rails r "puts User.count"`.strip
+
+ app_file "lib/tasks/count_user.rake", <<-RUBY
+ namespace :user do
+ task :count => :environment do
+ puts User.count
+ end
+ end
+ RUBY
+
+ assert_equal "0", `bundle exec rake user:count`.strip
+ end
+ end
end
end
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
index e50d744e26..4cdc6549db 100644
--- a/railties/test/application/routing_test.rb
+++ b/railties/test/application/routing_test.rb
@@ -229,6 +229,30 @@ module ApplicationTests
end
end
+ def test_root_path
+ app('development')
+
+ controller :foo, <<-RUBY
+ class FooController < ApplicationController
+ def index
+ render :text => "foo"
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do
+ get 'foo', :to => 'foo#index'
+ root :to => 'foo#index'
+ end
+ RUBY
+
+ remove_file 'public/index.html'
+
+ get '/'
+ assert_equal 'foo', last_response.body
+ end
+
test 'routes are added and removed when reloading' do
app('development')
diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb
index 4468fa295e..d086f13c82 100644
--- a/railties/test/application/runner_test.rb
+++ b/railties/test/application/runner_test.rb
@@ -57,5 +57,15 @@ module ApplicationTests
assert_match "script/program_name.rb", Dir.chdir(app_path) { `bundle exec rails runner "script/program_name.rb"` }
end
+
+ def test_with_hook
+ add_to_config <<-RUBY
+ runner do |app|
+ app.config.ran = true
+ end
+ RUBY
+
+ assert_match "true", Dir.chdir(app_path) { `bundle exec rails runner "puts Rails.application.config.ran"` }
+ end
end
end
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index 5891af505a..86f0962ac2 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -269,13 +269,27 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
assert_file "config/routes.rb", /\.routes\.draw do\s*\|map\|\s*$/
end
- def test_scaffold_generator_no_assets
+ def test_scaffold_generator_no_assets_with_switch_no_assets
run_generator [ "posts", "--no-assets" ]
assert_file "app/assets/stylesheets/scaffold.css"
assert_no_file "app/assets/javascripts/posts.js"
assert_no_file "app/assets/stylesheets/posts.css"
end
+ def test_scaffold_generator_no_assets_with_switch_assets_false
+ run_generator [ "posts", "--assets=false" ]
+ assert_file "app/assets/stylesheets/scaffold.css"
+ assert_no_file "app/assets/javascripts/posts.js"
+ assert_no_file "app/assets/stylesheets/posts.css"
+ end
+
+ def test_scaffold_generator_no_assets_with_switch_resource_route_false
+ run_generator [ "posts", "--resource-route=false" ]
+ assert_file "config/routes.rb" do |route|
+ assert_no_match(/resources :posts$/, route)
+ end
+ end
+
def test_scaffold_generator_no_stylesheets
run_generator [ "posts", "--no-stylesheets" ]
assert_no_file "app/assets/stylesheets/scaffold.css"
diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb
index 55f85c7202..335a74a609 100644
--- a/railties/test/railties/railtie_test.rb
+++ b/railties/test/railties/railtie_test.rb
@@ -163,6 +163,22 @@ module RailtiesTest
assert $ran_block
end
+ test "runner block is executed when MyApp.load_runner is called" do
+ $ran_block = false
+
+ class MyTie < Rails::Railtie
+ runner do
+ $ran_block = true
+ end
+ end
+
+ require "#{app_path}/config/environment"
+
+ assert !$ran_block
+ AppTemplate::Application.load_runner
+ assert $ran_block
+ end
+
test "railtie can add initializers" do
$ran_block = false