aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actioncable/lib/action_cable/channel/base.rb2
-rw-r--r--actioncable/test/channel/rejection_test.rb15
-rw-r--r--actionpack/CHANGELOG.md39
-rw-r--r--actionpack/lib/action_controller.rb1
-rw-r--r--actionpack/lib/action_controller/base.rb1
-rw-r--r--actionpack/lib/action_controller/metal/etag_with_flash.rb16
-rw-r--r--actionpack/lib/action_controller/test_case.rb9
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb86
-rw-r--r--actionpack/lib/action_dispatch/middleware/ssl.rb10
-rw-r--r--actionpack/test/controller/flash_test.rb29
-rw-r--r--actionpack/test/controller/test_case_test.rb9
-rw-r--r--actionpack/test/dispatch/ssl_test.rb14
-rw-r--r--activejob/CHANGELOG.md16
-rw-r--r--activejob/lib/active_job/exceptions.rb4
-rw-r--r--activerecord/CHANGELOG.md61
-rw-r--r--activerecord/lib/active_record/associations.rb6
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb88
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb112
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb6
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/column.rb24
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb4
-rw-r--r--activerecord/lib/active_record/querying.rb3
-rw-r--r--activerecord/lib/active_record/reflection.rb4
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb12
-rw-r--r--activerecord/lib/active_record/sanitization.rb5
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb13
-rw-r--r--activerecord/test/cases/adapters/mysql2/enum_test.rb5
-rw-r--r--activerecord/test/cases/adapters/postgresql/bit_string_test.rb5
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb4
-rw-r--r--activerecord/test/cases/associations/eager_test.rb22
-rw-r--r--activerecord/test/cases/column_definition_test.rb7
-rw-r--r--activerecord/test/cases/defaults_test.rb86
-rw-r--r--activerecord/test/cases/migration_test.rb17
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb27
-rw-r--r--activerecord/test/models/post.rb1
-rw-r--r--guides/assets/stylesheets/syntaxhighlighter/shCore.css2
-rw-r--r--guides/bug_report_templates/action_controller_master.rb1
-rw-r--r--guides/source/3_1_release_notes.md2
-rw-r--r--guides/source/action_cable_overview.md4
-rw-r--r--guides/source/active_job_basics.md7
-rw-r--r--guides/source/active_record_querying.md10
-rw-r--r--guides/source/asset_pipeline.md14
-rw-r--r--guides/source/development_dependencies_install.md43
-rw-r--r--guides/source/engines.md2
-rw-r--r--guides/source/getting_started.md4
-rw-r--r--guides/source/plugins.md2
-rw-r--r--guides/source/routing.md36
-rw-r--r--guides/source/security.md2
-rw-r--r--guides/source/testing.md6
-rw-r--r--guides/source/upgrading_ruby_on_rails.md2
-rw-r--r--railties/CHANGELOG.md9
-rw-r--r--railties/lib/rails/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt5
-rw-r--r--railties/test/railties/railtie_test.rb7
62 files changed, 553 insertions, 399 deletions
diff --git a/actioncable/lib/action_cable/channel/base.rb b/actioncable/lib/action_cable/channel/base.rb
index 8ab061171e..2e589a2cfa 100644
--- a/actioncable/lib/action_cable/channel/base.rb
+++ b/actioncable/lib/action_cable/channel/base.rb
@@ -247,7 +247,7 @@ module ActionCable
end
def processable_action?(action)
- self.class.action_methods.include?(action.to_s)
+ self.class.action_methods.include?(action.to_s) unless subscription_rejected?
end
def dispatch_action(action, data)
diff --git a/actioncable/test/channel/rejection_test.rb b/actioncable/test/channel/rejection_test.rb
index 0d2ac1c129..faf35ad048 100644
--- a/actioncable/test/channel/rejection_test.rb
+++ b/actioncable/test/channel/rejection_test.rb
@@ -7,6 +7,9 @@ class ActionCable::Channel::RejectionTest < ActiveSupport::TestCase
def subscribed
reject if params[:id] > 0
end
+
+ def secret_action
+ end
end
setup do
@@ -21,4 +24,16 @@ class ActionCable::Channel::RejectionTest < ActiveSupport::TestCase
expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" }
assert_equal expected, @connection.last_transmission
end
+
+ test "does not execute action if subscription is rejected" do
+ @connection.expects(:subscriptions).returns mock().tap { |m| m.expects(:remove_subscription).with instance_of(SecretChannel) }
+ @channel = SecretChannel.new @connection, "{id: 1}", id: 1
+
+ expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" }
+ assert_equal expected, @connection.last_transmission
+ assert_equal 1, @connection.transmissions.size
+
+ @channel.perform_action("action" => :secret_action)
+ assert_equal 1, @connection.transmissions.size
+ end
end
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 1fb7e20417..a66a1e8af3 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,42 @@
+* Include the content of the flash in the auto-generated etag. This solves the following problem:
+
+ 1. POST /messages
+ 2. redirect_to messages_url, notice: 'Message was created'
+ 3. GET /messages/1
+ 4. GET /messages
+
+ Step 4 would before still include the flash message, even though it's no longer relevant,
+ because the etag cache was recorded with the flash in place and didn't change when it was gone.
+
+ *DHH*
+
+* SSL: Changes redirect behavior for all non-GET and non-HEAD requests
+ (like POST/PUT/PATCH etc) to `http://` resources to redirect to `https://`
+ with a [307 status code](http://tools.ietf.org/html/rfc7231#section-6.4.7) instead of [301 status code](http://tools.ietf.org/html/rfc7231#section-6.4.2).
+
+ 307 status code instructs the HTTP clients to preserve the original
+ request method while redirecting. It has been part of HTTP RFC since
+ 1999 and is implemented/recognized by most (if not all) user agents.
+
+ # Before
+ POST http://example.com/articles (i.e. ArticlesContoller#create)
+ redirects to
+ GET https://example.com/articles (i.e. ArticlesContoller#index)
+
+ # After
+ POST http://example.com/articles (i.e. ArticlesContoller#create)
+ redirects to
+ POST https://example.com/articles (i.e. ArticlesContoller#create)
+
+ *Chirag Singhal*
+
+* Add `:as` option to `ActionController:TestCase#process` and related methods.
+
+ Specifying `as: mime_type` allows the `CONTENT_TYPE` header to be specified
+ in controller tests without manually doing this through `@request.headers['CONTENT_TYPE']`.
+
+ *Everest Stefan Munro-Zeisberger*
+
* Show cache hits and misses when rendering partials.
Partials using the `cache` helper will show whether a render hit or missed
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index fc86a907b3..50f20aa789 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -23,6 +23,7 @@ module ActionController
autoload :Cookies
autoload :DataStreaming
autoload :EtagWithTemplateDigest
+ autoload :EtagWithFlash
autoload :Flash
autoload :ForceSSL
autoload :Head
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 68a526eccb..ca8066cd82 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -213,6 +213,7 @@ module ActionController
Renderers::All,
ConditionalGet,
EtagWithTemplateDigest,
+ EtagWithFlash,
Caching,
MimeResponds,
ImplicitRender,
diff --git a/actionpack/lib/action_controller/metal/etag_with_flash.rb b/actionpack/lib/action_controller/metal/etag_with_flash.rb
new file mode 100644
index 0000000000..474d75f02e
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/etag_with_flash.rb
@@ -0,0 +1,16 @@
+module ActionController
+ # When you're using the flash, it's generally used as a conditional on the view.
+ # This means the content of the view depends on the flash. Which in turn means
+ # that the etag for a response should be computed with the content of the flash
+ # in mind. This does that by including the content of the flash as a component
+ # in the etag that's generated for a response.
+ module EtagWithFlash
+ extend ActiveSupport::Concern
+
+ include ActionController::ConditionalGet
+
+ included do
+ etag { flash unless flash.empty? }
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 83c32136dd..11a6cf8e15 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -449,6 +449,8 @@ module ActionController
# - +session+: A hash of parameters to store in the session. This may be +nil+.
# - +flash+: A hash of parameters to store in the flash. This may be +nil+.
# - +format+: Request format. Defaults to +nil+. Can be string or symbol.
+ # - +as+: Content type. Defaults to +nil+. Must be a symbol that corresponds
+ # to a mime type.
#
# Example calling +create+ action and sending two params:
#
@@ -469,7 +471,7 @@ module ActionController
check_required_ivars
if kwarg_request?(args)
- parameters, session, body, flash, http_method, format, xhr = args[0].values_at(:params, :session, :body, :flash, :method, :format, :xhr)
+ parameters, session, body, flash, http_method, format, xhr, as = args[0].values_at(:params, :session, :body, :flash, :method, :format, :xhr, :as)
else
http_method, parameters, session, flash = args
format = nil
@@ -514,6 +516,11 @@ module ActionController
@request.set_header "REQUEST_METHOD", http_method
+ if as
+ @request.content_type = Mime[as].to_s
+ format ||= as
+ end
+
parameters = parameters.symbolize_keys
generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action.to_s))
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index e85ea90b94..06ffa983d1 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -192,11 +192,7 @@ module ActionDispatch
# Returns the complete URL used for this request.
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
# req.url # => "http://example.com"
def url
protocol + host_with_port + fullpath
@@ -204,14 +200,10 @@ module ActionDispatch
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
# req.protocol # => "http://"
#
- # req = Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
# req.protocol # => "https://"
def protocol
@protocol ||= ssl? ? "https://" : "http://"
@@ -219,17 +211,13 @@ module ActionDispatch
# Returns the \host and port for this request, such as "example.com:8080".
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
# req.raw_host_with_port # => "example.com"
#
- # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
# req.raw_host_with_port # => "example.com:80"
#
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.raw_host_with_port # => "example.com:8080"
def raw_host_with_port
if forwarded = x_forwarded_host.presence
@@ -241,11 +229,7 @@ module ActionDispatch
# Returns the host for this request, such as "example.com".
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.host # => "example.com"
def host
raw_host_with_port.sub(/:\d+$/, "".freeze)
@@ -255,17 +239,13 @@ module ActionDispatch
# "example.com:8080". Port is only included if it is not a default port
# (80 or 443)
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
# req.host_with_port # => "example.com"
#
- # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
# req.host_with_port # => "example.com"
#
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.host_with_port # => "example.com:8080"
def host_with_port
"#{host}#{port_string}"
@@ -273,14 +253,10 @@ module ActionDispatch
# Returns the port number of this request as an integer.
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
# req.port # => 80
#
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.port # => 8080
def port
@port ||= begin
@@ -294,11 +270,7 @@ module ActionDispatch
# Returns the standard \port number for this request's protocol.
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.standard_port # => 80
def standard_port
case protocol
@@ -309,14 +281,10 @@ module ActionDispatch
# Returns whether this request is using the standard port
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
# req.standard_port? # => true
#
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.standard_port? # => false
def standard_port?
port == standard_port
@@ -325,14 +293,10 @@ module ActionDispatch
# Returns a number \port suffix like 8080 if the \port number of this request
# is not the default HTTP \port 80 or HTTPS \port 443.
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
# req.optional_port # => nil
#
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.optional_port # => 8080
def optional_port
standard_port? ? nil : port
@@ -341,14 +305,10 @@ module ActionDispatch
# Returns a string \port suffix, including colon, like ":8080" if the \port
# number of this request is not the default HTTP \port 80 or HTTPS \port 443.
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'HTTP_HOST' => 'example.com:80'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
# req.port_string # => ""
#
- # req = Request.new 'HTTP_HOST' => 'example.com:8080'
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
# req.port_string # => ":8080"
def port_string
standard_port? ? "" : ":#{port}"
@@ -356,14 +316,10 @@ module ActionDispatch
# Returns the requested port, such as 8080, based on SERVER_PORT
#
- # class Request < Rack::Request
- # include ActionDispatch::Http::URL
- # end
- #
- # req = Request.new 'SERVER_PORT' => '80'
+ # req = ActionDispatch::Request.new 'SERVER_PORT' => '80'
# req.server_port # => 80
#
- # req = Request.new 'SERVER_PORT' => '8080'
+ # req = ActionDispatch::Request.new 'SERVER_PORT' => '8080'
# req.server_port # => 8080
def server_port
get_header("SERVER_PORT").to_i
diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb
index 0b81d0ad43..992daab3aa 100644
--- a/actionpack/lib/action_dispatch/middleware/ssl.rb
+++ b/actionpack/lib/action_dispatch/middleware/ssl.rb
@@ -133,12 +133,20 @@ module ActionDispatch
end
def redirect_to_https(request)
- [ @redirect.fetch(:status, 301),
+ [ @redirect.fetch(:status, redirection_status(request)),
{ "Content-Type" => "text/html",
"Location" => https_location_for(request) },
@redirect.fetch(:body, []) ]
end
+ def redirection_status(request)
+ if request.get? || request.head?
+ 301 # Issue a permanent redirect via a GET request.
+ else
+ 307 # Issue a fresh request redirect to preserve the HTTP method.
+ end
+ end
+
def https_location_for(request)
host = @redirect[:host] || request.host
port = @redirect[:port] || request.port
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index cabbe2d608..e5f24f1a3a 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -263,6 +263,13 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
flash[:bar] = "for great justice"
head :ok
end
+
+ def set_flash_optionally
+ flash.now.notice = params[:flash]
+ if stale? etag: "abe"
+ render inline: "maybe flash"
+ end
+ end
end
def test_flash
@@ -310,6 +317,28 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest
end
end
+ def test_flash_factored_into_etag
+ with_test_route_set do
+ get "/set_flash_optionally"
+ no_flash_etag = response.etag
+
+ get "/set_flash_optionally", params: { flash: "hello!" }
+ hello_flash_etag = response.etag
+
+ assert_not_equal no_flash_etag, hello_flash_etag
+
+ get "/set_flash_optionally", params: { flash: "hello!" }
+ another_hello_flash_etag = response.etag
+
+ assert_equal another_hello_flash_etag, hello_flash_etag
+
+ get "/set_flash_optionally", params: { flash: "goodbye!" }
+ goodbye_flash_etag = response.etag
+
+ assert_not_equal another_hello_flash_etag, goodbye_flash_etag
+ end
+ end
+
private
# Overwrite get to send SessionSecret in env hash
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 2d78fc71a9..696794a3eb 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -637,6 +637,15 @@ XML
assert_equal "application/json", parsed_env["CONTENT_TYPE"]
end
+ def test_using_as_json_sets_request_content_type_to_json
+ post :render_body, params: { bool_value: true, str_value: "string", num_value: 2 }, as: :json
+
+ assert_equal "application/json", @request.headers["CONTENT_TYPE"]
+ assert_equal true, @request.request_parameters[:bool_value]
+ assert_equal "string", @request.request_parameters[:str_value]
+ assert_equal 2, @request.request_parameters[:num_value]
+ end
+
def test_mutating_content_type_headers_for_plain_text_files_sets_the_header
@request.headers["Content-Type"] = "text/plain"
post :render_body, params: { name: "foo.txt" }
diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb
index ccddb90bb5..71b274bf1e 100644
--- a/actionpack/test/dispatch/ssl_test.rb
+++ b/actionpack/test/dispatch/ssl_test.rb
@@ -38,6 +38,16 @@ class RedirectSSLTest < SSLTest
assert_equal redirect[:body].join, @response.body
end
+ def assert_post_redirected(redirect: {}, from: "http://a/b?c=d",
+ to: from.sub("http", "https"))
+
+ self.app = build_app ssl_options: { redirect: redirect }
+
+ post from
+ assert_response redirect[:status] || 307
+ assert_redirected_to to
+ end
+
test "exclude can avoid redirect" do
excluding = { exclude: -> request { request.path =~ /healthcheck/ } }
@@ -57,6 +67,10 @@ class RedirectSSLTest < SSLTest
assert_redirected
end
+ test "http POST is redirected to https with status 307" do
+ assert_post_redirected
+ end
+
test "redirect with non-301 status" do
assert_redirected redirect: { status: 307 }
end
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index 653149b6ee..9bf397af14 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -1,10 +1,15 @@
-## Rails 5.1.0.alpha ##
+* Added instance variable `@queue` to JobWrapper.
+
+ This will fix issues in [resque-scheduler](https://github.com/resque/resque-scheduler) `#job_to_hash` method,
+ so we can use `#enqueue_delayed_selection`, `#remove_delayed` method in resque-scheduler smoothly.
+
+ *mu29*
* Yield the job instance so you have access to things like `job.arguments` on the custom logic after retries fail.
*DHH*
-* Added declarative exception handling via `ActiveJob::Base.retry_on` and `ActiveJob::Base.discard_on`.
+* Added declarative exception handling via `ActiveJob::Base.retry_on` and `ActiveJob::Base.discard_on`.
Examples:
@@ -24,12 +29,5 @@
*DHH*
-* Added instance variable `@queue` to JobWrapper.
-
- This will fix issues in [resque-scheduler](https://github.com/resque/resque-scheduler) `#job_to_hash` method,
- so we can use `#enqueue_delayed_selection`, `#remove_delayed` method in resque-scheduler smoothly.
-
- *mu29*
-
Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/activejob/CHANGELOG.md) for previous changes.
diff --git a/activejob/lib/active_job/exceptions.rb b/activejob/lib/active_job/exceptions.rb
index f8d76587ad..d236f03d53 100644
--- a/activejob/lib/active_job/exceptions.rb
+++ b/activejob/lib/active_job/exceptions.rb
@@ -31,12 +31,12 @@ module ActiveJob
# retry_on(YetAnotherCustomAppException) do |job, exception|
# ExceptionNotifier.caught(exception)
# end
- # retry_on ActiveRecord::StatementInvalid, wait: 5.seconds, attempts: 3
+ # retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3
# retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10
#
# def perform(*args)
# # Might raise CustomAppException, AnotherCustomAppException, or YetAnotherCustomAppException for something domain specific
- # # Might raise ActiveRecord::StatementInvalid when a local db deadlock is detected
+ # # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected
# # Might raise Net::OpenTimeout when the remote service is down
# end
# end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 6b996fd6bd..4aa1853bde 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,58 @@
+* Remove standardized column types/arguments spaces in schema dump.
+
+ *Tim Petricola*
+
+* Avoid loading records from database when they are already loaded using
+ the `pluck` method on a collection.
+
+ Fixes #25921.
+
+ *Ryuta Kamizono*
+
+* Remove text default treated as an empty string in non-strict mode for
+ consistency with other types.
+
+ Strict mode controls how MySQL handles invalid or missing values in
+ data-change statements such as INSERT or UPDATE. If strict mode is not
+ in effect, MySQL inserts adjusted values for invalid or missing values
+ and produces warnings.
+
+ def test_mysql_not_null_defaults_non_strict
+ using_strict(false) do
+ with_mysql_not_null_table do |klass|
+ record = klass.new
+ assert_nil record.non_null_integer
+ assert_nil record.non_null_string
+ assert_nil record.non_null_text
+ assert_nil record.non_null_blob
+
+ record.save!
+ record.reload
+
+ assert_equal 0, record.non_null_integer
+ assert_equal "", record.non_null_string
+ assert_equal "", record.non_null_text
+ assert_equal "", record.non_null_blob
+ end
+ end
+ end
+
+ https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-strict
+
+ *Ryuta Kamizono*
+
+* Sqlite3 migrations to add a column to an existing table can now be
+ successfully rolled back when the column was given and invalid column
+ type.
+
+ Fixes #26087
+
+ *Travis O'Neill*
+
+* Deprecate `sanitize_conditions`. Use `sanitize_sql` instead.
+
+ *Ryuta Kamizono*
+
* Doing count on relations that contain LEFT OUTER JOIN Arel node no longer
force a DISTINCT. This solves issues when using count after a left_joins.
@@ -57,8 +112,8 @@
*Xavier Noria*
* Using `group` with an attribute that has a custom type will properly cast
- the hash keys after calling a calculation method like `count`.
-
+ the hash keys after calling a calculation method like `count`.
+
Fixes #25595.
*Sean Griffin*
@@ -93,7 +148,7 @@
*Sean Griffin*
* Ensure hashes can be assigned to attributes created using `composed_of`.
-
+
Fixes #25210.
*Sean Griffin*
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 659e512ce2..dc68b01386 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1296,6 +1296,12 @@ module ActiveRecord
# If using with the <tt>:through</tt> option, the association on the join model must be
# a #belongs_to, and the records which get deleted are the join records, rather than
# the associated records.
+ #
+ # If using <tt>dependent: :destroy</tt> on a scoped association, only the scoped objects are destroyed.
+ # For example, if a Post model defines
+ # <tt>has_many :comments, -> { where published: true }, dependent: :destroy</tt> and <tt>destroy</tt> is
+ # called on a post, only published comments are destroyed. This means that any unpublished comments in the
+ # database would still contain a foreign key pointing to the now deleted post.
# [:counter_cache]
# This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
# when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association.
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 7c688d663c..a02ec032a7 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -82,14 +82,6 @@ module ActiveRecord
@target = []
end
- def select(*fields)
- if block_given?
- load_target.select.each { |e| yield e }
- else
- scope.select(*fields)
- end
- end
-
def find(*args)
if block_given?
load_target.find(*args) { |*block_args| yield(*block_args) }
@@ -111,50 +103,6 @@ module ActiveRecord
end
end
- def first(limit = nil)
- find_nth_or_last(:first, limit)
- end
-
- def second
- find_nth_or_last(:second)
- end
-
- def third
- find_nth_or_last(:third)
- end
-
- def fourth
- find_nth_or_last(:fourth)
- end
-
- def fifth
- find_nth_or_last(:fifth)
- end
-
- def forty_two
- find_nth_or_last(:forty_two)
- end
-
- def third_to_last
- find_nth_or_last(:third_to_last)
- end
-
- def second_to_last
- find_nth_or_last(:second_to_last)
- end
-
- def last(limit = nil)
- find_nth_or_last(:last, limit)
- end
-
- def take(limit = nil)
- if find_from_target?
- limit ? load_target.take(limit) : load_target.first
- else
- scope.take(limit)
- end
- end
-
def build(attributes = {}, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| build(attr, &block) }
@@ -322,15 +270,6 @@ module ActiveRecord
end
end
- # Returns the size of the collection calling +size+ on the target.
- #
- # If the collection has been already loaded +length+ and +size+ are
- # equivalent. If not and you are going to need the records anyway this
- # method will take one less query. Otherwise +size+ is more efficient.
- def length
- load_target.size
- end
-
# Returns true if the collection is empty.
#
# If the collection has been loaded
@@ -453,6 +392,12 @@ module ActiveRecord
owner.new_record? && !foreign_key_present?
end
+ def find_from_target?
+ loaded? ||
+ owner.new_record? ||
+ target.any? { |record| record.new_record? || record.changed? }
+ end
+
private
def find_target
@@ -599,21 +544,6 @@ module ActiveRecord
owner.class.send(full_callback_name)
end
- # Should we deal with assoc.first or assoc.last by issuing an independent query to
- # the database, or by getting the target, and then taking the first/last item from that?
- #
- # If the args is just a non-empty options hash, go to the database.
- #
- # Otherwise, go to the database only if none of the following are true:
- # * target already loaded
- # * owner is new record
- # * target contains new or changed record(s)
- def find_from_target?
- loaded? ||
- owner.new_record? ||
- target.any? { |record| record.new_record? || record.changed? }
- end
-
def include_in_memory?(record)
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
assoc = owner.association(reflection.through_reflection.name)
@@ -640,12 +570,6 @@ module ActiveRecord
load_target.select { |r| ids.include?(r.id.to_s) }
end
end
-
- # Fetches the first/last using SQL if possible, otherwise from the target array.
- def find_nth_or_last(ordinal, limit = nil)
- collection = find_from_target? ? load_target : scope
- limit ? collection.send(ordinal, limit) : collection.send(ordinal)
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 36f6c1b9c3..ffdd1c04a3 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -53,6 +53,12 @@ module ActiveRecord
@association.loaded?
end
+ ##
+ # :method: select
+ #
+ # :call-seq:
+ # select(*fields, &block)
+ #
# Works in two ways.
#
# *First:* Specify a subset of fields to be selected from the result set.
@@ -106,9 +112,6 @@ module ActiveRecord
# # #<Pet id: 2, name: "Spook">,
# # #<Pet id: 3, name: "Choo-Choo">
# # ]
- def select(*fields, &block)
- @association.select(*fields, &block)
- end
# Finds an object in the collection responding to the +id+. Uses the same
# rules as ActiveRecord::Base.find. Returns ActiveRecord::RecordNotFound
@@ -140,6 +143,12 @@ module ActiveRecord
@association.find(*args, &block)
end
+ ##
+ # :method: first
+ #
+ # :call-seq:
+ # first(limit = nil)
+ #
# Returns the first record, or the first +n+ records, from the collection.
# If the collection is empty, the first form returns +nil+, and the second
# form returns an empty array.
@@ -166,45 +175,63 @@ module ActiveRecord
# another_person_without.pets # => []
# another_person_without.pets.first # => nil
# another_person_without.pets.first(3) # => []
- def first(limit = nil)
- @association.first(limit)
- end
+ ##
+ # :method: second
+ #
+ # :call-seq:
+ # second()
+ #
# Same as #first except returns only the second record.
- def second
- @association.second
- end
+ ##
+ # :method: third
+ #
+ # :call-seq:
+ # third()
+ #
# Same as #first except returns only the third record.
- def third
- @association.third
- end
+ ##
+ # :method: fourth
+ #
+ # :call-seq:
+ # fourth()
+ #
# Same as #first except returns only the fourth record.
- def fourth
- @association.fourth
- end
+ ##
+ # :method: fifth
+ #
+ # :call-seq:
+ # fifth()
+ #
# Same as #first except returns only the fifth record.
- def fifth
- @association.fifth
- end
+ ##
+ # :method: forty_two
+ #
+ # :call-seq:
+ # forty_two()
+ #
# Same as #first except returns only the forty second record.
# Also known as accessing "the reddit".
- def forty_two
- @association.forty_two
- end
+ ##
+ # :method: third_to_last
+ #
+ # :call-seq:
+ # third_to_last()
+ #
# Same as #first except returns only the third-to-last record.
- def third_to_last
- @association.third_to_last
- end
+ ##
+ # :method: second_to_last
+ #
+ # :call-seq:
+ # second_to_last()
+ #
# Same as #first except returns only the second-to-last record.
- def second_to_last
- @association.second_to_last
- end
# Returns the last record, or the last +n+ records, from the collection.
# If the collection is empty, the first form returns +nil+, and the second
@@ -233,7 +260,8 @@ module ActiveRecord
# another_person_without.pets.last # => nil
# another_person_without.pets.last(3) # => []
def last(limit = nil)
- @association.last(limit)
+ load_target if find_from_target?
+ super
end
# Gives a record (or N records if a parameter is supplied) from the collection
@@ -262,7 +290,8 @@ module ActiveRecord
# another_person_without.pets.take # => nil
# another_person_without.pets.take(2) # => []
def take(limit = nil)
- @association.take(limit)
+ load_target if find_from_target?
+ super
end
# Returns a new object of the collection type that has been instantiated
@@ -773,6 +802,12 @@ module ActiveRecord
@association.size
end
+ ##
+ # :method: length
+ #
+ # :call-seq:
+ # length()
+ #
# Returns the size of the collection calling +size+ on the target.
# If the collection has been already loaded, +length+ and +size+ are
# equivalent. If not and you are going to need the records anyway this
@@ -793,9 +828,6 @@ module ActiveRecord
# # #<Pet id: 2, name: "Spook", person_id: 1>,
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
# # ]
- def length
- @association.length
- end
# Returns +true+ if the collection is empty. If the collection has been
# loaded it is equivalent
@@ -1078,12 +1110,28 @@ module ActiveRecord
self
end
+ protected
+
+ def find_nth_with_limit(index, limit)
+ load_target if find_from_target?
+ super
+ end
+
+ def find_nth_from_last(index)
+ load_target if find_from_target?
+ super
+ end
+
private
def null_scope?
@association.null_scope?
end
+ def find_from_target?
+ @association.find_from_target?
+ end
+
def exec_queries
load_target
end
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 3946d5baa4..62acad0eda 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -274,7 +274,11 @@ module ActiveRecord
construct(model, node, row, rs, seen, model_cache, aliases)
else
model = construct_model(ar_parent, node, row, model_cache, id, aliases)
- model.readonly!
+
+ if node.reflection.scope_for(node.base_klass).readonly_value
+ model.readonly!
+ end
+
seen[ar_parent.object_id][node.base_klass][id] = model
construct(model, node, row, rs, seen, model_cache, aliases)
end
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index a8afa48865..4bb627f399 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -113,7 +113,7 @@ module ActiveRecord
end
def reflection_scope
- @reflection_scope ||= reflection.scope ? klass.unscoped.instance_exec(nil, &reflection.scope) : klass.unscoped
+ @reflection_scope ||= reflection.scope_for(klass)
end
def build_scope
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 126047584e..def1dadb6a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -379,7 +379,7 @@ module ActiveRecord
end
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
- [sql, binds, pk, sequence_name]
+ [sql, binds]
end
def last_inserted_id(result)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index d9a799676f..ffde4f2c93 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -303,7 +303,7 @@ module ActiveRecord
# end
def column(name, type, options = {})
name = name.to_s
- type = type.to_sym
+ type = type.to_sym if type
options = options.dup
if @columns_hash[name] && @columns_hash[name].primary_key?
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index afa0860707..45d782e45e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -1047,7 +1047,8 @@ module ActiveRecord
end
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
- if native = native_database_types[type.to_sym]
+ type = type.to_sym if type
+ if native = native_database_types[type]
column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
if type == :decimal # ignore limit, use precision and scale
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index f09c9c9e7f..3a28879c15 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -709,7 +709,7 @@ module ActiveRecord
end
def fetch_type_metadata(sql_type, extra = "")
- MySQL::TypeMetadata.new(super(sql_type), extra: extra, strict: strict_mode?)
+ MySQL::TypeMetadata.new(super(sql_type), extra: extra)
end
def add_index_length(quoted_columns, **options)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/column.rb b/activerecord/lib/active_record/connection_adapters/mysql/column.rb
index 5452e44c84..296d9a15f8 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/column.rb
@@ -2,21 +2,7 @@ module ActiveRecord
module ConnectionAdapters
module MySQL
class Column < ConnectionAdapters::Column # :nodoc:
- delegate :strict, :extra, to: :sql_type_metadata, allow_nil: true
-
- def initialize(*)
- super
- extract_default
- end
-
- def has_default?
- return false if blob_or_text_column? # MySQL forbids defaults on blob and text columns
- super
- end
-
- def blob_or_text_column?
- /\A(?:tiny|medium|long)?blob\b/ === sql_type || type == :text
- end
+ delegate :extra, to: :sql_type_metadata, allow_nil: true
def unsigned?
/\bunsigned\z/ === sql_type
@@ -29,14 +15,6 @@ module ActiveRecord
def auto_increment?
extra == "auto_increment"
end
-
- private
-
- def extract_default
- if blob_or_text_column?
- @default = null || strict ? nil : ""
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
index 1be5cb4740..24dcf852e1 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
@@ -2,13 +2,12 @@ module ActiveRecord
module ConnectionAdapters
module MySQL
class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
- attr_reader :extra, :strict
+ attr_reader :extra
- def initialize(type_metadata, extra: "", strict: false)
+ def initialize(type_metadata, extra: "")
super(type_metadata)
@type_metadata = type_metadata
@extra = extra
- @strict = strict
end
def ==(other)
@@ -24,7 +23,7 @@ module ActiveRecord
protected
def attributes_for_hash
- [self.class, @type_metadata, extra, strict]
+ [self.class, @type_metadata, extra]
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
index 46aca2ab54..7414eba6c5 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
@@ -124,14 +124,13 @@ module ActiveRecord
pk = primary_key(table_ref) if table_ref
end
- pk = suppress_composite_primary_key(pk)
-
- if pk && use_insert_returning?
+ if pk = suppress_composite_primary_key(pk)
sql = "#{sql} RETURNING #{quote_column_name(pk)}"
end
super
end
+ protected :sql_for_insert
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
if use_insert_returning? || pk == false
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
index a6b5a89ec0..74bff229ea 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
@@ -7,7 +7,7 @@ module ActiveRecord
:bit
end
- def cast(value)
+ def cast_value(value)
if ::String === value
case value
when /^0x/i
@@ -16,7 +16,7 @@ module ActiveRecord
value # Bit-string notation
end
else
- value
+ value.to_s
end
end
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index 7b4b8c60f8..dd7d650207 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -62,8 +62,7 @@ module ActiveRecord
#
# * +sql+ - An SQL statement which should return a count query from the database, see the example above.
def count_by_sql(sql)
- sql = sanitize_conditions(sql)
- connection.select_value(sql, "#{name} Count").to_i
+ connection.select_value(sanitize_sql(sql), "#{name} Count").to_i
end
end
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 3553ff4da3..8c5e4d042e 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -311,6 +311,10 @@ module ActiveRecord
active_record == other_aggregation.active_record
end
+ def scope_for(klass)
+ scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped
+ end
+
private
def derive_class_name
name.to_s.camelize
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index ff43def901..376867675b 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -97,7 +97,7 @@ module ActiveRecord
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
# Person.where(["name LIKE '%?'", name]).take
def take(limit = nil)
- limit ? limit(limit).to_a : find_take
+ limit ? find_take_with_limit(limit) : find_take
end
# Same as #take but raises ActiveRecord::RecordNotFound if no record
@@ -526,13 +526,21 @@ module ActiveRecord
end
end
+ def find_take_with_limit(limit)
+ if loaded?
+ records.take(limit)
+ else
+ limit(limit).to_a
+ end
+ end
+
def find_nth(index)
@offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
end
def find_nth_with_limit(index, limit)
if loaded?
- records[index, limit]
+ records[index, limit] || []
else
relation = if order_values.empty? && primary_key
order(arel_attribute(primary_key).asc)
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index c40e98715e..7f596120eb 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -29,8 +29,9 @@ module ActiveRecord
else condition
end
end
- alias_method :sanitize_sql, :sanitize_sql_for_conditions
- alias_method :sanitize_conditions, :sanitize_sql
+ alias :sanitize_sql :sanitize_sql_for_conditions
+ alias :sanitize_conditions :sanitize_sql
+ deprecate sanitize_conditions: :sanitize_sql
# Accepts an array, hash, or string of SQL conditions and sanitizes
# them into a valid SQL fragment for a SET clause.
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 01f788a424..b65d5b56f1 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -146,20 +146,13 @@ HEADER
keys = @connection.migration_keys
# figure out the lengths for each column based on above keys
- lengths = keys.map { |key|
- column_specs.map { |spec|
- spec[key] ? spec[key].length + 2 : 0
- }.max
- }
+ lengths = [0] * keys.length
# the string we're going to sprintf our values against, with standardized column widths
- format_string = lengths.map { |len| "%-#{len}s" }
-
- # find the max length for the 'type' column, which is special
- type_length = column_specs.map { |column| column[:type].length }.max
+ format_string = ["%s"] * keys.length
# add column type definition to our format string
- format_string.unshift " t.%-#{type_length}s "
+ format_string.unshift " t.%s "
format_string *= ""
diff --git a/activerecord/test/cases/adapters/mysql2/enum_test.rb b/activerecord/test/cases/adapters/mysql2/enum_test.rb
index 9f51223d58..7ad3e3ca2d 100644
--- a/activerecord/test/cases/adapters/mysql2/enum_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb
@@ -9,11 +9,6 @@ class Mysql2EnumTest < ActiveRecord::Mysql2TestCase
assert_equal 8, column.limit
end
- def test_should_not_be_blob_or_text_column
- column = EnumTest.columns_hash["enum_column"]
- assert_not column.blob_or_text_column?
- end
-
def test_should_not_be_unsigned
column = EnumTest.columns_hash["enum_column"]
assert_not column.unsigned?
diff --git a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb
index f646e59848..7712e809a2 100644
--- a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb
@@ -65,10 +65,11 @@ class PostgresqlBitStringTest < ActiveRecord::PostgreSQLTestCase
end
def test_roundtrip
- PostgresqlBitString.create! a_bit: "00001010", a_bit_varying: "0101"
- record = PostgresqlBitString.first
+ record = PostgresqlBitString.create!(a_bit: "00001010", a_bit_varying: "0101")
assert_equal "00001010", record.a_bit
assert_equal "0101", record.a_bit_varying
+ assert_nil record.another_bit
+ assert_nil record.another_bit_varying
record.a_bit = "11111111"
record.a_bit_varying = "0xF"
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index 4b8d06be4b..e6af93a53e 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -88,12 +88,6 @@ module ActiveRecord
assert_equal expect.to_i, result.rows.first.first
end
- def test_sql_for_insert_with_returning_disabled
- connection = connection_without_insert_returning
- sql, binds = connection.sql_for_insert("sql", nil, nil, nil, "binds")
- assert_equal ["sql", "binds"], [sql, binds]
- end
-
def test_serial_sequence
assert_equal "public.accounts_id_seq",
@connection.serial_sequence("accounts", "id")
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index 321b74c1f5..9a59691737 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -198,13 +198,13 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase
def test_schema_dumper_for_uuid_primary_key
schema = dump_table_schema "pg_uuids"
assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: -> { "uuid_generate_v1\(\)" }/, schema)
- assert_match(/t\.uuid "other_uuid", default: -> { "uuid_generate_v4\(\)" }/, schema)
+ assert_match(/t\.uuid "other_uuid", default: -> { "uuid_generate_v4\(\)" }/, schema)
end
def test_schema_dumper_for_uuid_primary_key_with_custom_default
schema = dump_table_schema "pg_uuids_2"
assert_match(/\bcreate_table "pg_uuids_2", id: :uuid, default: -> { "my_uuid_generator\(\)" }/, schema)
- assert_match(/t\.uuid "other_uuid_2", default: -> { "my_uuid_generator\(\)" }/, schema)
+ assert_match(/t\.uuid "other_uuid_2", default: -> { "my_uuid_generator\(\)" }/, schema)
end
end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 2c826acf96..6011c552b2 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -1424,6 +1424,24 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert david.readonly_comments.first.readonly?
end
+ test "eager-loading non-readonly association" do
+ # has_one
+ firm = Firm.where(id: "1").eager_load(:account).first!
+ assert_not firm.account.readonly?
+
+ # has_and_belongs_to_many
+ project = Project.where(id: "2").eager_load(:developers).first!
+ assert_not project.developers.first.readonly?
+
+ # has_many :through
+ david = Author.where(id: "1").eager_load(:comments).first!
+ assert_not david.comments.first.readonly?
+
+ # belongs_to
+ post = Post.where(id: "1").eager_load(:author).first!
+ assert_not post.author.readonly?
+ end
+
test "eager-loading readonly association" do
# has-one
firm = Firm.where(id: "1").eager_load(:readonly_account).first!
@@ -1438,8 +1456,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert david.readonly_comments.first.readonly?
# belongs_to
- post = Post.where(id: "1").eager_load(:author).first!
- assert post.author.readonly?
+ post = Post.where(id: "1").eager_load(:readonly_author).first!
+ assert post.readonly_author.readonly?
end
test "preloading a polymorphic association with references to the associated table" do
diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb
index 989beaa5c8..a65bb89052 100644
--- a/activerecord/test/cases/column_definition_test.rb
+++ b/activerecord/test/cases/column_definition_test.rb
@@ -60,14 +60,13 @@ module ActiveRecord
end
def test_should_not_set_default_for_blob_and_text_data_types
- text_type = MySQL::TypeMetadata.new(
- SqlTypeMetadata.new(type: :text))
+ text_type = MySQL::TypeMetadata.new(SqlTypeMetadata.new(type: :text))
text_column = MySQL::Column.new("title", nil, text_type)
- assert_equal nil, text_column.default
+ assert_nil text_column.default
not_null_text_column = MySQL::Column.new("title", nil, text_type, false)
- assert_equal "", not_null_text_column.default
+ assert_nil not_null_text_column.default
end
def test_has_default_should_return_false_for_blob_and_text_data_types
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index f94815d34c..fcaff38f82 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -127,92 +127,66 @@ if current_adapter?(:Mysql2Adapter)
ActiveRecord::Base.establish_connection connection
end
- # MySQL cannot have defaults on text/blob columns. It reports the
- # default value as null.
+ # Strict mode controls how MySQL handles invalid or missing values
+ # in data-change statements such as INSERT or UPDATE. A value can be
+ # invalid for several reasons. For example, it might have the wrong
+ # data type for the column, or it might be out of range. A value is
+ # missing when a new row to be inserted does not contain a value for
+ # a non-NULL column that has no explicit DEFAULT clause in its definition.
+ # (For a NULL column, NULL is inserted if the value is missing.)
#
- # Despite this, in non-strict mode, MySQL will use an empty string
- # as the default value of the field, if no other value is
- # specified.
+ # If strict mode is not in effect, MySQL inserts adjusted values for
+ # invalid or missing values and produces warnings. In strict mode,
+ # you can produce this behavior by using INSERT IGNORE or UPDATE IGNORE.
#
- # Therefore, in non-strict mode, we want column.default to report
- # an empty string as its default, to be consistent with that.
- #
- # In strict mode, column.default should be nil.
- def test_mysql_text_not_null_defaults_non_strict
+ # https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-strict
+ def test_mysql_not_null_defaults_non_strict
using_strict(false) do
- with_text_blob_not_null_table do |klass|
+ with_mysql_not_null_table do |klass|
record = klass.new
- assert_equal "", record.non_null_blob
- assert_equal "", record.non_null_text
-
- assert_nil record.null_blob
- assert_nil record.null_text
+ assert_nil record.non_null_integer
+ assert_nil record.non_null_string
+ assert_nil record.non_null_text
+ assert_nil record.non_null_blob
record.save!
record.reload
+ assert_equal 0, record.non_null_integer
+ assert_equal "", record.non_null_string
assert_equal "", record.non_null_text
assert_equal "", record.non_null_blob
-
- assert_nil record.null_text
- assert_nil record.null_blob
end
end
end
- def test_mysql_text_not_null_defaults_strict
+ def test_mysql_not_null_defaults_strict
using_strict(true) do
- with_text_blob_not_null_table do |klass|
+ with_mysql_not_null_table do |klass|
record = klass.new
- assert_nil record.non_null_blob
+ assert_nil record.non_null_integer
+ assert_nil record.non_null_string
assert_nil record.non_null_text
- assert_nil record.null_blob
- assert_nil record.null_text
+ assert_nil record.non_null_blob
assert_raises(ActiveRecord::StatementInvalid) { klass.create }
end
end
end
- def with_text_blob_not_null_table
+ def with_mysql_not_null_table
klass = Class.new(ActiveRecord::Base)
- klass.table_name = "test_mysql_text_not_null_defaults"
+ klass.table_name = "test_mysql_not_null_defaults"
klass.connection.create_table klass.table_name do |t|
- t.column :non_null_text, :text, null: false
- t.column :non_null_blob, :blob, null: false
- t.column :null_text, :text, null: true
- t.column :null_blob, :blob, null: true
+ t.integer :non_null_integer, null: false
+ t.string :non_null_string, null: false
+ t.text :non_null_text, null: false
+ t.blob :non_null_blob, null: false
end
yield klass
ensure
klass.connection.drop_table(klass.table_name) rescue nil
end
-
- # MySQL uses an implicit default 0 rather than NULL unless in strict mode.
- # We use an implicit NULL so schema.rb is compatible with other databases.
- def test_mysql_integer_not_null_defaults
- klass = Class.new(ActiveRecord::Base)
- klass.table_name = "test_integer_not_null_default_zero"
- klass.connection.create_table klass.table_name do |t|
- t.column :zero, :integer, null: false, default: 0
- t.column :omit, :integer, null: false
- end
-
- assert_equal "0", klass.columns_hash["zero"].default
- assert !klass.columns_hash["zero"].null
- assert_equal nil, klass.columns_hash["omit"].default
- assert !klass.columns_hash["omit"].null
-
- assert_raise(ActiveRecord::StatementInvalid) { klass.create! }
-
- assert_nothing_raised do
- instance = klass.create!(omit: 1)
- assert_equal 0, instance.zero
- assert_equal 1, instance.omit
- end
- ensure
- klass.connection.drop_table(klass.table_name) rescue nil
- end
end
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 76a4592ac5..151f3c8efd 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -551,6 +551,23 @@ class MigrationTest < ActiveRecord::TestCase
end
end
+ if current_adapter?(:SQLite3Adapter)
+ def test_allows_sqlite3_rollback_on_invalid_column_type
+ Person.connection.create_table :something, force: true do |t|
+ t.column :number, :integer
+ t.column :name, :string
+ t.column :foo, :bar
+ end
+ assert Person.connection.column_exists?(:something, :foo)
+ assert_nothing_raised { Person.connection.remove_column :something, :foo, :bar }
+ assert !Person.connection.column_exists?(:something, :foo)
+ assert Person.connection.column_exists?(:something, :name)
+ assert Person.connection.column_exists?(:something, :number)
+ ensure
+ Person.connection.drop_table :something, if_exists: true
+ end
+ end
+
if current_adapter? :OracleAdapter
def test_create_table_with_custom_sequence_name
# table name is 29 chars, the standard sequence name will
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 33baf84ef2..57b1bc889a 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -70,38 +70,35 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r{create_table "CamelCase"}, output
end
- def assert_line_up(lines, pattern, required = false)
+ def assert_no_line_up(lines, pattern)
return assert(true) if lines.empty?
matches = lines.map { |line| line.match(pattern) }
- assert matches.all? if required
matches.compact!
return assert(true) if matches.empty?
- assert_equal 1, matches.map { |match| match.offset(0).first }.uniq.length
+ line_matches = lines.map { |line| [line, line.match(pattern)] }.select { |line, match| match }
+ assert line_matches.all? { |line, match|
+ start = match.offset(0).first
+ line[start - 2..start - 1] == ", "
+ }
end
def column_definition_lines(output = standard_dump)
output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map { |m| m.last.split(/\n/) }
end
- def test_types_line_up
+ def test_types_no_line_up
column_definition_lines.each do |column_set|
next if column_set.empty?
- lengths = column_set.map do |column|
- if match = column.match(/\bt\.\w+\s+(?="\w+?")/)
- match[0].length
- end
- end.compact
-
- assert_equal 1, lengths.uniq.length
+ assert column_set.all? { |column| !column.match(/\bt\.\w+\s{2,}/) }
end
end
- def test_arguments_line_up
+ def test_arguments_no_line_up
column_definition_lines.each do |column_set|
- assert_line_up(column_set, /default: /)
- assert_line_up(column_set, /limit: /)
- assert_line_up(column_set, /null: /)
+ assert_no_line_up(column_set, /default: /)
+ assert_no_line_up(column_set, /limit: /)
+ assert_no_line_up(column_set, /null: /)
end
end
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 42eff9cff9..66a99cbcda 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -24,6 +24,7 @@ class Post < ActiveRecord::Base
scope :limit_by, lambda { |l| limit(l) }
belongs_to :author
+ belongs_to :readonly_author, -> { readonly }, class_name: "Author", foreign_key: :author_id
belongs_to :author_with_posts, -> { includes(:posts) }, class_name: "Author", foreign_key: :author_id
belongs_to :author_with_address, -> { includes(:author_address) }, class_name: "Author", foreign_key: :author_id
diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCore.css b/guides/assets/stylesheets/syntaxhighlighter/shCore.css
index 34f6864a15..7e1e199343 100644
--- a/guides/assets/stylesheets/syntaxhighlighter/shCore.css
+++ b/guides/assets/stylesheets/syntaxhighlighter/shCore.css
@@ -33,7 +33,7 @@
height: auto !important;
left: auto !important;
line-height: 1.1em !important;
- margin: 0 !important;
+ margin: 0 0 0.5px 0 !important;
outline: 0 !important;
overflow: visible !important;
padding: 0 !important;
diff --git a/guides/bug_report_templates/action_controller_master.rb b/guides/bug_report_templates/action_controller_master.rb
index cd0a3be85c..486c7243ad 100644
--- a/guides/bug_report_templates/action_controller_master.rb
+++ b/guides/bug_report_templates/action_controller_master.rb
@@ -14,7 +14,6 @@ require "action_controller/railtie"
class TestApp < Rails::Application
config.root = File.dirname(__FILE__)
- config.session_store :cookie_store, key: "cookie_store_key"
secrets.secret_token = "secret_token"
secrets.secret_key_base = "secret_key_base"
diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md
index feee0f9920..fd90cf9886 100644
--- a/guides/source/3_1_release_notes.md
+++ b/guides/source/3_1_release_notes.md
@@ -99,7 +99,7 @@ gem 'jquery-rails'
# config.assets.manifest = YOUR_PATH
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
- # config.assets.precompile `= %w( search.js )
+ # config.assets.precompile `= %w( admin.js admin.css )
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md
index 118b0b52b2..4b9a22101a 100644
--- a/guides/source/action_cable_overview.md
+++ b/guides/source/action_cable_overview.md
@@ -510,10 +510,10 @@ WebNotificationsChannel.broadcast_to(
The `WebNotificationsChannel.broadcast_to` call places a message in the current
subscription adapter's pubsub queue under a separate broadcasting name for each
user. For a user with an ID of 1, the broadcasting name would be
-"web_notifications_1".
+`web_notifications:1`.
The channel has been instructed to stream everything that arrives at
-"web_notifications_1" directly to the client by invoking the `received`
+`web_notifications:1` directly to the client by invoking the `received`
callback. The data passed as argument is the hash sent as the second parameter
to the server-side broadcast call, JSON encoded for the trip across the wire,
and unpacked for the data argument arriving to `received`.
diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md
index c9f70dc87b..c65d1e6de5 100644
--- a/guides/source/active_job_basics.md
+++ b/guides/source/active_job_basics.md
@@ -34,8 +34,9 @@ Delayed Job and Resque. Picking your queuing backend becomes more of an operatio
concern, then. And you'll be able to switch between them without having to rewrite
your jobs.
-NOTE: Rails by default comes with an "immediate runner" queuing implementation.
-That means that each job that has been enqueued will run immediately.
+NOTE: Rails by default comes with an asynchronous queuing implementation that
+runs jobs with an in-process thread pool. Jobs will run asynchronously, but any
+jobs in the queue will be dropped upon restart.
Creating a Job
@@ -109,7 +110,7 @@ That's it!
Job Execution
-------------
-For enqueuing and executing jobs in production you need to set up a queuing backend,
+For enqueuing and executing jobs in production you need to set up a queuing backend,
that is to say you need to decide for a 3rd-party queuing library that Rails should use.
Rails itself only provides an in-process queuing system, which only keeps the jobs in RAM.
If the process crashes or the machine is reset, then all outstanding jobs are lost with the
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index 6f941d0e4e..493fd526fb 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -84,7 +84,7 @@ The methods are:
* `distinct`
* `where`
-All of the above methods return an instance of `ActiveRecord::Relation`.
+Finder methods that return a collection, such as `where` and `group`, return an instance of `ActiveRecord::Relation`. Methods that find a single entity, such as `find` and `first`, return a single instance of the model.
The primary operation of `Model.find(options)` can be summarized as:
@@ -1014,13 +1014,13 @@ There are multiple ways to use the `joins` method.
You can just supply the raw SQL specifying the `JOIN` clause to `joins`:
```ruby
-Author.joins("INNER JOIN posts ON posts.author_id = author.id AND posts.published = 't'")
+Author.joins("INNER JOIN posts ON posts.author_id = authors.id AND posts.published = 't'")
```
This will result in the following SQL:
```sql
-SELECT clients.* FROM clients INNER JOIN posts ON posts.author_id = author.id AND posts.published = 't'
+SELECT clients.* FROM clients INNER JOIN posts ON posts.author_id = authors.id AND posts.published = 't'
```
#### Using Array/Hash of Named Associations
@@ -1251,9 +1251,9 @@ articles, all the articles would still be loaded. By using `joins` (an INNER
JOIN), the join conditions **must** match, otherwise no records will be
returned.
-NOTE: If an association is eager loaded as part of a join, any fields from a custom select clause will not present be on the loaded models.
+NOTE: If an association is eager loaded as part of a join, any fields from a custom select clause will not present be on the loaded models.
This is because it is ambiguous whether they should appear on the parent record, or the child.
-
+
Scopes
------
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index e6631a513c..701304acde 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -485,7 +485,7 @@ which contains these lines:
Rails creates both `app/assets/javascripts/application.js` and
`app/assets/stylesheets/application.css` regardless of whether the
---skip-sprockets option is used when creating a new rails application. This is
+--skip-sprockets option is used when creating a new Rails application. This is
so you can easily add asset pipelining later if you like.
The directives that work in JavaScript files also work in stylesheets
@@ -724,7 +724,7 @@ If you have other manifests or individual stylesheets and JavaScript files to
include, you can add them to the `precompile` array in `config/initializers/assets.rb`:
```ruby
-Rails.application.config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js']
+Rails.application.config.assets.precompile += %w( admin.js admin.css )
```
NOTE. Always specify an expected compiled filename that ends with .js or .css,
@@ -1024,7 +1024,7 @@ to tell our CDN (and browser) that the asset is "public", that means any cache
can store the request. Also we commonly want to set `max-age` which is how long
the cache will store the object before invalidating the cache. The `max-age`
value is set to seconds with a maximum possible value of `31536000` which is one
-year. You can do this in your rails application by setting
+year. You can do this in your Rails application by setting
```
config.public_file_server.headers = {
@@ -1109,9 +1109,9 @@ Windows you have a JavaScript runtime installed in your operating system.
### Serving GZipped version of assets
-By default, gzipped version of compiled assets will be generated, along
-with the non-gzipped version of assets. Gzipped assets help reduce the transmission of
-data over the wire. You can configure this by setting the `gzip` flag.
+By default, gzipped version of compiled assets will be generated, along with
+the non-gzipped version of assets. Gzipped assets help reduce the transmission
+of data over the wire. You can configure this by setting the `gzip` flag.
```ruby
config.assets.gzip = false # disable gzipped assets generation
@@ -1291,7 +1291,7 @@ config.assets.digest = true
# Precompile additional assets (application.js, application.css, and all
# non-JS/CSS are already added)
-# config.assets.precompile += %w( search.js )
+# config.assets.precompile += %w( admin.js admin.css )
```
Rails 4 and above no longer set default config values for Sprockets in `test.rb`, so
diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md
index cc24e6f666..20cd34c182 100644
--- a/guides/source/development_dependencies_install.md
+++ b/guides/source/development_dependencies_install.md
@@ -288,3 +288,46 @@ NOTE: Using the rake task to create the test databases ensures they have the cor
NOTE: You'll see the following warning (or localized warning) during activating HStore extension in PostgreSQL 9.1.x or earlier: "WARNING: => is deprecated as an operator".
If you're using another database, check the file `activerecord/test/config.yml` or `activerecord/test/config.example.yml` for default connection information. You can edit `activerecord/test/config.yml` to provide different credentials on your machine if you must, but obviously you should not push any such changes back to Rails.
+
+### Action Cable Setup
+
+Action Cable uses Redis as its default subscriptions adapter ([read more](action_cable_overview.html#broadcasting)). Thus, in order to have Action Cable's tests passing you need to install and have Redis running.
+
+#### Install Redis From Source
+
+Redis' documentation discourage installations with package managers as those are usually outdated. Installing from source and bringing the server up is straight forward and well documented on [Redis' documentation](http://redis.io/download#installation).
+
+#### Install Redis From Package Manager
+
+On OS X, you can run:
+
+```bash
+$ brew install redis
+```
+
+Follow the instructions given by Homebrew to start these.
+
+In Ubuntu just run:
+
+```bash
+$ sudo apt-get install redis-server
+```
+
+On Fedora or CentOS (requires EPEL enabled), just run:
+
+```bash
+$ sudo yum install redis
+```
+
+If you are running Arch Linux just run:
+
+```bash
+$ sudo pacman -S redis
+$ sudo systemctl start redis
+```
+
+FreeBSD users will have to run the following:
+
+```bash
+# portmaster databases/redis
+```
diff --git a/guides/source/engines.md b/guides/source/engines.md
index f9a37e45ac..d6118c014f 100644
--- a/guides/source/engines.md
+++ b/guides/source/engines.md
@@ -1364,7 +1364,7 @@ You can define assets for precompilation in `engine.rb`:
```ruby
initializer "blorgh.assets.precompile" do |app|
- app.config.assets.precompile += %w(admin.css admin.js)
+ app.config.assets.precompile += %w( admin.js admin.css )
end
```
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index d56b817bad..54421a328c 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -485,7 +485,7 @@ to find a template called `articles/new` within `app/views` for the
application. The format for this template can only be `html` and the default
handler for HTML is `erb`. Rails uses other handlers for other formats.
`builder` handler is used to build XML templates and `coffee` handler uses
-CoffeeScript to build JavaScript templates. Because you want to create a new
+CoffeeScript to build JavaScript templates. Since you want to create a new
HTML form, you will be using the `ERB` language which is designed to embed Ruby
in HTML.
@@ -528,7 +528,7 @@ method called `form_for`. To use this method, add this code into
<% end %>
```
-If you refresh the page now, you'll see the exact same form as in the example.
+If you refresh the page now, you'll see the exact same form from our example above.
Building forms in Rails is really just that easy!
When you call `form_for`, you pass it an identifying object for this
diff --git a/guides/source/plugins.md b/guides/source/plugins.md
index ff84861b8c..760ff431c0 100644
--- a/guides/source/plugins.md
+++ b/guides/source/plugins.md
@@ -67,7 +67,7 @@ This will tell you that everything got generated properly and you are ready to s
Extending Core Classes
----------------------
-This section will explain how to add a method to String that will be available anywhere in your rails application.
+This section will explain how to add a method to String that will be available anywhere in your Rails application.
In this example you will add a method to String named `to_squawk`. To begin, create a new test file with a few assertions:
diff --git a/guides/source/routing.md b/guides/source/routing.md
index 756e0fefd7..937e313663 100644
--- a/guides/source/routing.md
+++ b/guides/source/routing.md
@@ -553,29 +553,23 @@ In particular, simple routing makes it very easy to map legacy URLs to new Rails
### Bound Parameters
-When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: `:controller` maps to the name of a controller in your application, and `:action` maps to the name of an action within that controller. For example, consider this route:
+When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. For example, consider this route:
```ruby
-get ':controller(/:action(/:id))'
+get 'photos(/:id)', to: :display
```
-If an incoming request of `/photos/show/1` is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the `show` action of the `PhotosController`, and to make the final parameter `"1"` available as `params[:id]`. This route will also route the incoming request of `/photos` to `PhotosController#index`, since `:action` and `:id` are optional parameters, denoted by parentheses.
+If an incoming request of `/photos/1` is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the `display` action of the `PhotosController`, and to make the final parameter `"1"` available as `params[:id]`. This route will also route the incoming request of `/photos` to `PhotosController#display`, since `:id` is an optional parameter, denoted by parentheses.
### Dynamic Segments
-You can set up as many dynamic segments within a regular route as you like. Anything other than `:controller` or `:action` will be available to the action as part of `params`. If you set up this route:
+You can set up as many dynamic segments within a regular route as you like. Any segment will be available to the action as part of `params`. If you set up this route:
```ruby
-get ':controller/:action/:id/:user_id'
+get 'photos/:id/:user_id', to: 'photos#show'
```
-An incoming path of `/photos/show/1/2` will be dispatched to the `show` action of the `PhotosController`. `params[:id]` will be `"1"`, and `params[:user_id]` will be `"2"`.
-
-NOTE: You can't use `:namespace` or `:module` with a `:controller` path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g:
-
-```ruby
-get ':controller(/:action(/:id))', controller: /admin\/[^\/]+/
-```
+An incoming path of `/photos/1/2` will be dispatched to the `show` action of the `PhotosController`. `params[:id]` will be `"1"`, and `params[:user_id]` will be `"2"`.
TIP: By default, dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `id: /[^\/]+/` allows anything except a slash.
@@ -584,32 +578,24 @@ TIP: By default, dynamic segments don't accept dots - this is because the dot is
You can specify static segments when creating a route by not prepending a colon to a fragment:
```ruby
-get ':controller/:action/:id/with_user/:user_id'
+get 'photos/:id/with_user/:user_id', to: 'photos#show'
```
-This route would respond to paths such as `/photos/show/1/with_user/2`. In this case, `params` would be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`.
+This route would respond to paths such as `/photos/1/with_user/2`. In this case, `params` would be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`.
### The Query String
The `params` will also include any parameters from the query string. For example, with this route:
```ruby
-get ':controller/:action/:id'
+get 'photos/:id', to: 'photos#show'
```
-An incoming path of `/photos/show/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`.
+An incoming path of `/photos/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`.
### Defining Defaults
-You do not need to explicitly use the `:controller` and `:action` symbols within a route. You can supply them as defaults:
-
-```ruby
-get 'photos/:id', to: 'photos#show'
-```
-
-With this route, Rails will match an incoming path of `/photos/12` to the `show` action of `PhotosController`.
-
-You can also define other defaults in a route by supplying a hash for the `:defaults` option. This even applies to parameters that you do not specify as dynamic segments. For example:
+You can define defaults in a route by supplying a hash for the `:defaults` option. This even applies to parameters that you do not specify as dynamic segments. For example:
```ruby
get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' }
diff --git a/guides/source/security.md b/guides/source/security.md
index 2d1bc3b5b3..36eb61be8b 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -965,7 +965,7 @@ When `params[:token]` is one of: `[nil]`, `[nil, nil, ...]` or
`['foo', nil]` it will bypass the test for `nil`, but `IS NULL` or
`IN ('foo', NULL)` where clauses still will be added to the SQL query.
-To keep rails secure by default, `deep_munge` replaces some of the values with
+To keep Rails secure by default, `deep_munge` replaces some of the values with
`nil`. Below table shows what the parameters look like based on `JSON` sent in
request:
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 26d50bec0c..4ca3236ec1 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -37,10 +37,12 @@ controllers/ helpers/ mailers/ test_helper.rb
fixtures/ integration/ models/
```
-The `models` directory is meant to hold tests for your models, the `controllers` directory is meant to hold tests for your controllers and the `integration` directory is meant to hold tests that involve any number of controllers interacting. There is also a directory for testing your mailers and one for testing view helpers.
+The `helpers`, `mailers`, and `models` directories are meant to hold tests for view helpers, mailers, and models, respectively. The `controllers` directory is meant to hold tests for controllers, routes, and views. The `integration` directory is meant to hold tests for interactions between controllers.
Fixtures are a way of organizing test data; they reside in the `fixtures` directory.
+A `jobs` directory will also be created when an associated test is first generated.
+
The `test_helper.rb` file holds the default configuration for your tests.
@@ -1085,7 +1087,7 @@ end
Testing Routes
--------------
-Like everything else in your Rails application, you can test your routes.
+Like everything else in your Rails application, you can test your routes. Route tests reside in `test/controllers/` or are part of controller tests.
NOTE: If your application has complex routes, Rails provides a number of useful helpers to test them.
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index a8afa0ca6e..2372590cec 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -1426,7 +1426,7 @@ config.assets.digest = true
# config.assets.manifest = YOUR_PATH
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
-# config.assets.precompile += %w( search.js )
+# config.assets.precompile += %w( admin.js admin.css )
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 70f4b84237..594d239290 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Run `before_configuration` callbacks as soon as application constant
+ inherits from `Rails::Application`.
+
+ Fixes #19880.
+
+ *Yuji Yaginuma*
+
* A generated app should not include Uglifier with `--skip-javascript` option.
*Ben Pickles*
@@ -17,7 +24,7 @@
*John Meehan*
-* Display name of the class defining the initializer along with the initializer
+* Display name of the class defining the initializer along with the initializer
name in the output of `rails initializers`.
Before:
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 9c150965bf..b01196e3ed 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -87,6 +87,7 @@ module Rails
super
Rails.app_class = base
add_lib_to_load_path!(find_root(base.called_from))
+ ActiveSupport.run_load_hooks(:before_configuration, base)
end
def instance
@@ -146,7 +147,6 @@ module Rails
def run_load_hooks! # :nodoc:
return self if @ran_load_hooks
@ran_load_hooks = true
- ActiveSupport.run_load_hooks(:before_configuration, self)
@initial_variable_values.each do |variable_name, value|
if INITIAL_VARIABLES.include?(variable_name)
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt
index 01ef3e6630..2318cf59ff 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt
@@ -7,5 +7,6 @@ Rails.application.config.assets.version = '1.0'
# Rails.application.config.assets.paths << Emoji.images_path
# Precompile additional assets.
-# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
-# Rails.application.config.assets.precompile += %w( search.js )
+# application.js, application.css, and all non-JS/CSS in the app/assets
+# folder are already added.
+# Rails.application.config.assets.precompile += %w( admin.js admin.css )
diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb
index 994019267c..755ac23cb1 100644
--- a/railties/test/railties/railtie_test.rb
+++ b/railties/test/railties/railtie_test.rb
@@ -79,6 +79,13 @@ module RailtiesTest
assert_equal app_path, $before_configuration
end
+ test "before_configuration callbacks run as soon as the application constant inherits from Rails::Application" do
+ $before_configuration = false
+ class Foo < Rails::Railtie ; config.before_configuration { $before_configuration = true } ; end
+ class Application < Rails::Application ; end
+ assert $before_configuration
+ end
+
test "railtie can add after_initialize callbacks" do
$after_initialize = false
class Foo < Rails::Railtie ; config.after_initialize { $after_initialize = true } ; end