aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actioncable/CHANGELOG.md19
-rw-r--r--actioncable/lib/action_cable/channel/broadcasting.rb26
-rw-r--r--actioncable/lib/action_cable/channel/streams.rb2
-rw-r--r--actioncable/lib/action_cable/channel/test_case.rb10
-rw-r--r--actioncable/lib/action_cable/connection/test_case.rb2
-rw-r--r--actioncable/test/channel/broadcasting_test.rb15
-rw-r--r--actioncable/test/channel/test_case_test.rb2
-rw-r--r--actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb2
-rw-r--r--actionmailbox/app/views/layouts/rails/conductor.html.erb1
-rw-r--r--actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb31
-rw-r--r--actionmailbox/test/dummy/config/puma.rb2
-rw-r--r--actionpack/CHANGELOG.md10
-rw-r--r--actionpack/lib/action_controller/metal/basic_implicit_render.rb2
-rw-r--r--actionpack/lib/action_controller/metal/force_ssl.rb3
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb4
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb33
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb9
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb6
-rw-r--r--actionpack/test/controller/log_subscriber_test.rb4
-rw-r--r--actionpack/test/controller/new_base/render_context_test.rb55
-rw-r--r--actionpack/test/controller/redirect_test.rb44
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb44
-rw-r--r--actionpack/test/dispatch/live_response_test.rb2
-rw-r--r--actionpack/test/journey/router_test.rb6
-rw-r--r--actiontext/app/helpers/action_text/tag_helper.rb4
-rw-r--r--actiontext/app/models/action_text/rich_text.rb4
-rw-r--r--actiontext/app/views/active_storage/blobs/_blob.html.erb2
-rw-r--r--actiontext/test/dummy/config/puma.rb2
-rw-r--r--actionview/lib/action_view/base.rb18
-rw-r--r--actionview/lib/action_view/context.rb5
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb10
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionview/lib/action_view/renderer/streaming_template_renderer.rb4
-rw-r--r--actionview/lib/action_view/renderer/template_renderer.rb12
-rw-r--r--actionview/lib/action_view/rendering.rb4
-rw-r--r--actionview/lib/action_view/template.rb14
-rw-r--r--actionview/lib/action_view/template/handlers/erb/erubi.rb10
-rw-r--r--actionview/test/abstract_unit.rb2
-rw-r--r--actionview/test/actionpack/controller/render_test.rb10
-rw-r--r--actionview/test/template/template_test.rb2
-rw-r--r--activemodel/CHANGELOG.md28
-rw-r--r--activemodel/lib/active_model/type/time.rb2
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb11
-rw-r--r--activemodel/test/cases/type/time_test.rb1
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb30
-rw-r--r--activerecord/lib/active_record/migration/compatibility.rb4
-rw-r--r--activerecord/lib/active_record/persistence.rb4
-rw-r--r--activerecord/lib/active_record/relation/query_attribute.rb2
-rw-r--r--activerecord/lib/arel/nodes/and.rb2
-rw-r--r--activerecord/lib/arel/nodes/case.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/active_schema_test.rb13
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb14
-rw-r--r--activerecord/test/cases/arel/nodes/and_test.rb9
-rw-r--r--activerecord/test/cases/arel/nodes/case_test.rb10
-rw-r--r--activerecord/test/cases/statement_cache_test.rb6
-rw-r--r--activerecord/test/cases/type/time_test.rb22
-rw-r--r--activestorage/README.md2
-rw-r--r--activestorage/app/models/active_storage/blob/representable.rb10
-rw-r--r--activestorage/app/models/active_storage/preview.rb2
-rw-r--r--activestorage/app/models/active_storage/variant.rb8
-rw-r--r--activestorage/app/models/active_storage/variation.rb2
-rw-r--r--activestorage/test/controllers/blobs_controller_test.rb25
-rw-r--r--activestorage/test/controllers/representations_controller_test.rb30
-rw-r--r--guides/CHANGELOG.md8
-rw-r--r--guides/source/active_storage_overview.md2
-rw-r--r--guides/source/caching_with_rails.md4
-rw-r--r--guides/source/development_dependencies_install.md1
-rw-r--r--guides/source/rails_on_rack.md2
-rw-r--r--guides/source/testing.md33
-rw-r--r--railties/CHANGELOG.md5
-rw-r--r--railties/lib/rails/application/configuration.rb2
-rw-r--r--railties/lib/rails/command/base.rb14
-rw-r--r--railties/lib/rails/generators/app_base.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt2
-rw-r--r--railties/lib/rails/tasks/statistics.rake3
-rw-r--r--railties/test/application/configuration_test.rb5
-rw-r--r--railties/test/application/rake_test.rb2
-rw-r--r--railties/test/command/base_test.rb2
-rw-r--r--tasks/release.rb2
83 files changed, 500 insertions, 323 deletions
diff --git a/actioncable/CHANGELOG.md b/actioncable/CHANGELOG.md
index 4109dd6138..7f3177b64e 100644
--- a/actioncable/CHANGELOG.md
+++ b/actioncable/CHANGELOG.md
@@ -1,3 +1,22 @@
+* Add `Channel::Base#broadcast_to`.
+
+ You can now call `broadcast_to` within a channel action, which equals to
+ the `self.class.broadcast_to`.
+
+ *Vladimir Dementyev*
+
+* Make `Channel::Base.broadcasting_for` a public API.
+
+ You can use `.broadcasting_for` to generate a unique stream identifier within
+ a channel for the specified target (e.g. Active Record model):
+
+ ```ruby
+ ChatChannel.broadcasting_for(model) # => "chat:<model.to_gid_param>"
+ ```
+
+ *Vladimir Dementyev*
+
+
## Rails 6.0.0.beta1 (January 18, 2019) ##
* Merge [`action-cable-testing`](https://github.com/palkan/action-cable-testing) to Rails.
diff --git a/actioncable/lib/action_cable/channel/broadcasting.rb b/actioncable/lib/action_cable/channel/broadcasting.rb
index 9a96720f4a..9f702e425e 100644
--- a/actioncable/lib/action_cable/channel/broadcasting.rb
+++ b/actioncable/lib/action_cable/channel/broadcasting.rb
@@ -7,22 +7,32 @@ module ActionCable
module Broadcasting
extend ActiveSupport::Concern
- delegate :broadcasting_for, to: :class
+ delegate :broadcasting_for, :broadcast_to, to: :class
module ClassMethods
# Broadcast a hash to a unique broadcasting for this <tt>model</tt> in this channel.
def broadcast_to(model, message)
- ActionCable.server.broadcast(broadcasting_for([ channel_name, model ]), message)
+ ActionCable.server.broadcast(broadcasting_for(model), message)
end
- def broadcasting_for(model) #:nodoc:
+ # Returns a unique broadcasting identifier for this <tt>model</tt> in this channel:
+ #
+ # CommentsChannel.broadcasting_for("all") # => "comments:all"
+ #
+ # You can pass any object as a target (e.g. Active Record model), and it
+ # would be serialized into a string under the hood.
+ def broadcasting_for(model)
+ serialize_broadcasting([ channel_name, model ])
+ end
+
+ def serialize_broadcasting(object) #:nodoc:
case
- when model.is_a?(Array)
- model.map { |m| broadcasting_for(m) }.join(":")
- when model.respond_to?(:to_gid_param)
- model.to_gid_param
+ when object.is_a?(Array)
+ object.map { |m| serialize_broadcasting(m) }.join(":")
+ when object.respond_to?(:to_gid_param)
+ object.to_gid_param
else
- model.to_param
+ object.to_param
end
end
end
diff --git a/actioncable/lib/action_cable/channel/streams.rb b/actioncable/lib/action_cable/channel/streams.rb
index 81c2c38064..7e1ed3c850 100644
--- a/actioncable/lib/action_cable/channel/streams.rb
+++ b/actioncable/lib/action_cable/channel/streams.rb
@@ -99,7 +99,7 @@ module ActionCable
# Pass <tt>coder: ActiveSupport::JSON</tt> to decode messages as JSON before passing to the callback.
# Defaults to <tt>coder: nil</tt> which does no decoding, passes raw messages.
def stream_for(model, callback = nil, coder: nil, &block)
- stream_from(broadcasting_for([ channel_name, model ]), callback || block, coder: coder)
+ stream_from(broadcasting_for(model), callback || block, coder: coder)
end
# Unsubscribes all streams associated with this channel from the pubsub queue.
diff --git a/actioncable/lib/action_cable/channel/test_case.rb b/actioncable/lib/action_cable/channel/test_case.rb
index c4cf0ac0e7..b05d51a61a 100644
--- a/actioncable/lib/action_cable/channel/test_case.rb
+++ b/actioncable/lib/action_cable/channel/test_case.rb
@@ -143,7 +143,7 @@ module ActionCable
# You need to set up your connection manually to provide values for the identifiers.
# To do this just use:
#
- # stub_connection(user: users[:john])
+ # stub_connection(user: users(:john))
#
# == Testing broadcasting
#
@@ -157,9 +157,9 @@ module ActionCable
# end
#
# def test_speak
- # subscribe room_id: rooms[:chat].id
+ # subscribe room_id: rooms(:chat).id
#
- # assert_broadcasts_on(rooms[:chat], text: "Hello, Rails!") do
+ # assert_broadcasts_on(rooms(:chat), text: "Hello, Rails!") do
# perform :speak, message: "Hello, Rails!"
# end
# end
@@ -300,9 +300,7 @@ module ActionCable
def broadcasting_for(stream_or_object)
return stream_or_object if stream_or_object.is_a?(String)
- self.class.channel_class.broadcasting_for(
- [self.class.channel_class.channel_name, stream_or_object]
- )
+ self.class.channel_class.broadcasting_for(stream_or_object)
end
end
diff --git a/actioncable/lib/action_cable/connection/test_case.rb b/actioncable/lib/action_cable/connection/test_case.rb
index 26a183d1ec..8d25a55c8a 100644
--- a/actioncable/lib/action_cable/connection/test_case.rb
+++ b/actioncable/lib/action_cable/connection/test_case.rb
@@ -42,8 +42,6 @@ module ActionCable
class TestRequest < ActionDispatch::TestRequest
attr_accessor :session, :cookie_jar
-
- attr_writer :cookie_jar
end
module TestConnection
diff --git a/actioncable/test/channel/broadcasting_test.rb b/actioncable/test/channel/broadcasting_test.rb
index 2cbfabc1d0..fb501a1bc2 100644
--- a/actioncable/test/channel/broadcasting_test.rb
+++ b/actioncable/test/channel/broadcasting_test.rb
@@ -26,14 +26,23 @@ class ActionCable::Channel::BroadcastingTest < ActionCable::TestCase
end
test "broadcasting_for with an object" do
- assert_equal "Room#1-Campfire", ChatChannel.broadcasting_for(Room.new(1))
+ assert_equal(
+ "action_cable:channel:broadcasting_test:chat:Room#1-Campfire",
+ ChatChannel.broadcasting_for(Room.new(1))
+ )
end
test "broadcasting_for with an array" do
- assert_equal "Room#1-Campfire:Room#2-Campfire", ChatChannel.broadcasting_for([ Room.new(1), Room.new(2) ])
+ assert_equal(
+ "action_cable:channel:broadcasting_test:chat:Room#1-Campfire:Room#2-Campfire",
+ ChatChannel.broadcasting_for([ Room.new(1), Room.new(2) ])
+ )
end
test "broadcasting_for with a string" do
- assert_equal "hello", ChatChannel.broadcasting_for("hello")
+ assert_equal(
+ "action_cable:channel:broadcasting_test:chat:hello",
+ ChatChannel.broadcasting_for("hello")
+ )
end
end
diff --git a/actioncable/test/channel/test_case_test.rb b/actioncable/test/channel/test_case_test.rb
index 9c360d5dc3..a166c41e11 100644
--- a/actioncable/test/channel/test_case_test.rb
+++ b/actioncable/test/channel/test_case_test.rb
@@ -180,7 +180,7 @@ class BroadcastsTestChannel < ActionCable::Channel::Base
def broadcast_to_user(data)
user = User.new user_id
- self.class.broadcast_to user, text: data["message"]
+ broadcast_to user, text: data["message"]
end
end
diff --git a/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb b/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb
index 2cde3db8a0..d051dfe665 100644
--- a/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb
+++ b/actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb
@@ -22,7 +22,7 @@ module Rails
def new_mail
Mail.new(params.require(:mail).permit(:from, :to, :cc, :bcc, :in_reply_to, :subject, :body).to_h).tap do |mail|
params[:mail][:attachments].to_a.each do |attachment|
- mail.attachments[attachment.original_filename] = { filename: attachment.path, content_type: attachment.content_type }
+ mail.add_file(filename: attachment.path, content: attachment.read)
end
end
end
diff --git a/actionmailbox/app/views/layouts/rails/conductor.html.erb b/actionmailbox/app/views/layouts/rails/conductor.html.erb
index 75157feb78..1cad6560c4 100644
--- a/actionmailbox/app/views/layouts/rails/conductor.html.erb
+++ b/actionmailbox/app/views/layouts/rails/conductor.html.erb
@@ -4,4 +4,5 @@
</head>
<body>
<%= yield %>
+</body>
</html>
diff --git a/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb b/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb
index 60077d86e2..fcd9ad839f 100644
--- a/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb
+++ b/actionmailbox/test/controllers/rails/action_mailbox/inbound_emails_controller_test.rb
@@ -10,16 +10,39 @@ class Rails::Conductor::ActionMailbox::InboundEmailsControllerTest < ActionDispa
mail: {
from: "Jason Fried <jason@37signals.com>",
to: "Replies <replies@example.com>",
- bcc: "",
in_reply_to: "<4e6e35f5a38b4_479f13bb90078178@small-app-01.mail>",
- subject: "Discussion: Let's debate these attachments",
+ subject: "Hey there",
+ body: "How's it going?"
+ }
+ }
+ end
+
+ mail = ActionMailbox::InboundEmail.last.mail
+ assert_equal %w[ jason@37signals.com ], mail.from
+ assert_equal %w[ replies@example.com ], mail.to
+ assert_equal "4e6e35f5a38b4_479f13bb90078178@small-app-01.mail", mail.in_reply_to
+ assert_equal "Hey there", mail.subject
+ assert_equal "How's it going?", mail.body.decoded
+ end
+ end
+
+ test "create inbound email with attachments" do
+ with_rails_env("development") do
+ assert_difference -> { ActionMailbox::InboundEmail.count }, +1 do
+ post rails_conductor_inbound_emails_path, params: {
+ mail: {
+ from: "Jason Fried <jason@37signals.com>",
+ to: "Replies <replies@example.com>",
+ subject: "Let's debate some attachments",
body: "Let's talk about these images:",
- attachments: [fixture_file_upload("files/avatar1.jpeg"), fixture_file_upload("files/avatar2.jpeg")]
+ attachments: [ fixture_file_upload("files/avatar1.jpeg"), fixture_file_upload("files/avatar2.jpeg") ]
}
}
end
- assert_equal 2, ActionMailbox::InboundEmail.last.mail.attachments.size
+ mail = ActionMailbox::InboundEmail.last.mail
+ assert_equal "Let's talk about these images:", mail.text_part.decoded
+ assert_equal 2, mail.attachments.count
end
end
diff --git a/actionmailbox/test/dummy/config/puma.rb b/actionmailbox/test/dummy/config/puma.rb
index a5eccf816b..71ed69a895 100644
--- a/actionmailbox/test/dummy/config/puma.rb
+++ b/actionmailbox/test/dummy/config/puma.rb
@@ -16,7 +16,7 @@ port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the number of `workers` to boot in clustered mode.
-# Workers are forked webserver processes. If using threads and workers together
+# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 1a1b1034aa..1d2f6b09c3 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -11,12 +11,6 @@
*Rafael Mendonça França*
-* Ensure external redirects are explicitly allowed
-
- Add `fallback_location` and `allow_other_host` options to `redirect_to`.
-
- *Gannon McGibbon*
-
* Introduce ActionDispatch::HostAuthorization
This is a new middleware that guards against DNS rebinding attacks by
@@ -82,7 +76,7 @@
* Apply mapping to symbols returned from dynamic CSP sources
Previously if a dynamic source returned a symbol such as :self it
- would be converted to a string implicity, e.g:
+ would be converted to a string implicitly, e.g:
policy.default_src -> { :self }
@@ -135,7 +129,7 @@
*Assain Jaleel*
-* Raises `ActionController::RespondToMismatchError` with confliciting `respond_to` invocations.
+* Raises `ActionController::RespondToMismatchError` with conflicting `respond_to` invocations.
`respond_to` can match multiple types and lead to undefined behavior when
multiple invocations are made and the types do not match:
diff --git a/actionpack/lib/action_controller/metal/basic_implicit_render.rb b/actionpack/lib/action_controller/metal/basic_implicit_render.rb
index 2dc990f303..f9a758ff0e 100644
--- a/actionpack/lib/action_controller/metal/basic_implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/basic_implicit_render.rb
@@ -6,7 +6,7 @@ module ActionController
super.tap { default_render unless performed? }
end
- def default_render(*args)
+ def default_render
head :no_content
end
end
diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb
index 205f84ae36..93fd57b640 100644
--- a/actionpack/lib/action_controller/metal/force_ssl.rb
+++ b/actionpack/lib/action_controller/metal/force_ssl.rb
@@ -13,7 +13,7 @@ module ActionController
ACTION_OPTIONS = [:only, :except, :if, :unless]
URL_OPTIONS = [:protocol, :host, :domain, :subdomain, :port, :path]
- REDIRECT_OPTIONS = [:status, :flash, :alert, :notice, :allow_other_host]
+ REDIRECT_OPTIONS = [:status, :flash, :alert, :notice]
module ClassMethods # :nodoc:
def force_ssl(options = {})
@@ -41,7 +41,6 @@ module ActionController
host: request.host,
path: request.fullpath,
status: :moved_permanently,
- allow_other_host: true,
}
if host_or_options.is_a?(Hash)
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index d3bb58f48b..8365ddca57 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -30,9 +30,9 @@ module ActionController
# :stopdoc:
include BasicImplicitRender
- def default_render(*args)
+ def default_render
if template_exists?(action_name.to_s, _prefixes, variants: request.variant)
- render(*args)
+ render
elsif any_templates?(action_name.to_s, _prefixes)
message = "#{self.class.name}\##{action_name} is missing a template " \
"for this request format and variant.\n" \
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 8bd003f5ed..67c198d150 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -60,7 +60,7 @@ module ActionController
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_options)
- self.location = _compute_safe_redirect_to_location(request, options, response_options)
+ self.location = _compute_redirect_to_location(request, options)
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
end
@@ -88,13 +88,9 @@ module ActionController
# All other options that can be passed to <tt>redirect_to</tt> are accepted as
# options and the behavior is identical.
def redirect_back(fallback_location:, allow_other_host: true, **args)
- referer = request.headers.fetch("Referer", fallback_location)
- response_options = {
- fallback_location: fallback_location,
- allow_other_host: allow_other_host,
- **args,
- }
- redirect_to referer, response_options
+ referer = request.headers["Referer"]
+ redirect_to_referer = referer && (allow_other_host || _url_host_allowed?(referer))
+ redirect_to redirect_to_referer ? referer : fallback_location, **args
end
def _compute_redirect_to_location(request, options) #:nodoc:
@@ -118,23 +114,6 @@ module ActionController
public :_compute_redirect_to_location
private
- def _compute_safe_redirect_to_location(request, options, response_options)
- location = _compute_redirect_to_location(request, options)
- location_options = options.is_a?(Hash) ? options : {}
- if response_options[:allow_other_host] || _url_host_allowed?(location, location_options)
- location
- else
- fallback_location = response_options.fetch(:fallback_location) do
- raise ArgumentError, <<~MSG.squish
- Unsafe redirect #{location.inspect},
- use :fallback_location to specify a fallback
- or :allow_other_host to redirect anyway.
- MSG
- end
- _compute_redirect_to_location(request, fallback_location)
- end
- end
-
def _extract_redirect_to_status(options, response_options)
if options.is_a?(Hash) && options.key?(:status)
Rack::Utils.status_code(options.delete(:status))
@@ -145,8 +124,8 @@ module ActionController
end
end
- def _url_host_allowed?(url, options = {})
- URI(url.to_s).host.in?([request.host, options[:host]])
+ def _url_host_allowed?(url)
+ URI(url.to_s).host == request.host
rescue ArgumentError, URI::Error
false
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index af41521c5c..28cde6704e 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -160,9 +160,16 @@ module ActionDispatch
@controller.singleton_class.include(_routes.url_helpers)
if @controller.respond_to? :view_context_class
- @controller.view_context_class = Class.new(@controller.view_context_class) do
+ view_context_class = Class.new(@controller.view_context_class) do
include _routes.url_helpers
end
+
+ custom_view_context = Module.new {
+ define_method(:view_context_class) do
+ view_context_class
+ end
+ }
+ @controller.extend(custom_view_context)
end
end
yield @routes
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index c7aae034dd..ecb8c37e6b 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -28,13 +28,13 @@ class ActionPackAssertionsController < ActionController::Base
def redirect_to_path() redirect_to "/some/path" end
- def redirect_invalid_external_route() redirect_to "ht_tp://www.rubyonrails.org", allow_other_host: true end
+ def redirect_invalid_external_route() redirect_to "ht_tp://www.rubyonrails.org" end
def redirect_to_named_route() redirect_to route_one_url end
- def redirect_external() redirect_to "http://www.rubyonrails.org", allow_other_host: true; end
+ def redirect_external() redirect_to "http://www.rubyonrails.org"; end
- def redirect_external_protocol_relative() redirect_to "//www.rubyonrails.org", allow_other_host: true; end
+ def redirect_external_protocol_relative() redirect_to "//www.rubyonrails.org"; end
def response404() head "404 AWOL" end
diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index cbebc6b59c..0562c16284 100644
--- a/actionpack/test/controller/log_subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -25,11 +25,11 @@ module Another
end
def redirector
- redirect_to "http://foo.bar/", allow_other_host: true
+ redirect_to "http://foo.bar/"
end
def filterable_redirector
- redirect_to "http://secret.foo.bar/", allow_other_host: true
+ redirect_to "http://secret.foo.bar/"
end
def data_sender
diff --git a/actionpack/test/controller/new_base/render_context_test.rb b/actionpack/test/controller/new_base/render_context_test.rb
deleted file mode 100644
index 5e570a1d79..0000000000
--- a/actionpack/test/controller/new_base/render_context_test.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-require "abstract_unit"
-
-# This is testing the decoupling of view renderer and view context
-# by allowing the controller to be used as view context. This is
-# similar to the way sinatra renders templates.
-module RenderContext
- class BasicController < ActionController::Base
- self.view_paths = [ActionView::FixtureResolver.new(
- "render_context/basic/hello_world.html.erb" => "<%= @value %> from <%= self.__controller_method__ %>",
- "layouts/basic.html.erb" => "?<%= yield %>?"
- )]
-
- # 1) Include ActionView::Context to bring the required dependencies
- include ActionView::Context
-
- # 2) Call _prepare_context that will do the required initialization
- before_action :_prepare_context
-
- def hello_world
- @value = "Hello"
- render action: "hello_world", layout: false
- end
-
- def with_layout
- @value = "Hello"
- render action: "hello_world", layout: "basic"
- end
-
- protected def __controller_method__
- "controller context!"
- end
-
- private
- # 3) Set view_context to self
- def view_context
- self
- end
- end
-
- class RenderContextTest < Rack::TestCase
- test "rendering using the controller as context" do
- get "/render_context/basic/hello_world"
- assert_body "Hello from controller context!"
- assert_status 200
- end
-
- test "rendering using the controller as context with layout" do
- get "/render_context/basic/with_layout"
- assert_body "?Hello from controller context!?"
- assert_status 200
- end
- end
-end
diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb
index 945d2275c0..998498e1b2 100644
--- a/actionpack/test/controller/redirect_test.rb
+++ b/actionpack/test/controller/redirect_test.rb
@@ -49,11 +49,11 @@ class RedirectController < ActionController::Base
end
def url_redirect_with_status
- redirect_to("http://www.example.com", status: :moved_permanently, allow_other_host: true)
+ redirect_to("http://www.example.com", status: :moved_permanently)
end
def url_redirect_with_status_hash
- redirect_to("http://www.example.com", status: 301, allow_other_host: true)
+ redirect_to("http://www.example.com", status: 301)
end
def relative_url_redirect_with_status
@@ -81,27 +81,19 @@ class RedirectController < ActionController::Base
end
def redirect_to_url
- redirect_to "http://www.rubyonrails.org/", allow_other_host: true
- end
-
- def redirect_to_unsafe_url
redirect_to "http://www.rubyonrails.org/"
end
- def redirect_to_relative_unsafe_url
- redirect_to ".br"
- end
-
def redirect_to_url_with_unescaped_query_string
- redirect_to "http://example.com/query?status=new", allow_other_host: true
+ redirect_to "http://example.com/query?status=new"
end
def redirect_to_url_with_complex_scheme
- redirect_to "x-test+scheme.complex:redirect", allow_other_host: true
+ redirect_to "x-test+scheme.complex:redirect"
end
def redirect_to_url_with_network_path_reference
- redirect_to "//www.rubyonrails.org/", allow_other_host: true
+ redirect_to "//www.rubyonrails.org/"
end
def redirect_to_existing_record
@@ -121,12 +113,12 @@ class RedirectController < ActionController::Base
end
def redirect_to_with_block
- redirect_to proc { "http://www.rubyonrails.org/" }, allow_other_host: true
+ redirect_to proc { "http://www.rubyonrails.org/" }
end
def redirect_to_with_block_and_assigns
@url = "http://www.rubyonrails.org/"
- redirect_to proc { @url }, allow_other_host: true
+ redirect_to proc { @url }
end
def redirect_to_with_block_and_options
@@ -253,28 +245,6 @@ class RedirectTest < ActionController::TestCase
assert_redirected_to "http://www.rubyonrails.org/"
end
- def test_redirect_to_unsafe_url
- error = assert_raises(ArgumentError) do
- get :redirect_to_unsafe_url
- end
- assert_equal <<~MSG.squish, error.message
- Unsafe redirect \"http://www.rubyonrails.org/\",
- use :fallback_location to specify a fallback or
- :allow_other_host to redirect anyway.
- MSG
- end
-
- def test_redirect_to_relative_unsafe_url
- error = assert_raises(ArgumentError) do
- get :redirect_to_relative_unsafe_url
- end
- assert_equal <<~MSG.squish, error.message
- Unsafe redirect \"http://test.host.br\",
- use :fallback_location to specify a fallback or
- :allow_other_host to redirect anyway.
- MSG
- end
-
def test_redirect_to_url_with_unescaped_query_string
get :redirect_to_url_with_unescaped_query_string
assert_response :redirect
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index c326f276bf..214e063276 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -8,7 +8,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
class Boomer
attr_accessor :closed
- def initialize(detailed = false)
+ def initialize(detailed = false)
@detailed = detailed
@closed = false
end
@@ -39,52 +39,50 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
def call(env)
env["action_dispatch.show_detailed_exceptions"] = @detailed
req = ActionDispatch::Request.new(env)
+ template = ActionView::Template.new(File.read(__FILE__), __FILE__, ActionView::Template::Handlers::Raw.new, {})
+
case req.path
- when %r{/pass}
+ when "/pass"
[404, { "X-Cascade" => "pass" }, self]
- when %r{/not_found}
+ when "/not_found"
raise AbstractController::ActionNotFound
- when %r{/runtime_error}
+ when "/runtime_error"
raise RuntimeError
- when %r{/method_not_allowed}
+ when "/method_not_allowed"
raise ActionController::MethodNotAllowed
- when %r{/intercepted_error}
+ when "/intercepted_error"
raise InterceptedErrorInstance
- when %r{/unknown_http_method}
+ when "/unknown_http_method"
raise ActionController::UnknownHttpMethod
- when %r{/not_implemented}
+ when "/not_implemented"
raise ActionController::NotImplemented
- when %r{/unprocessable_entity}
+ when "/unprocessable_entity"
raise ActionController::InvalidAuthenticityToken
- when %r{/not_found_original_exception}
+ when "/not_found_original_exception"
begin
raise AbstractController::ActionNotFound.new
rescue
- raise ActionView::Template::Error.new("template")
+ raise ActionView::Template::Error.new(template)
end
- when %r{/missing_template}
+ when "/missing_template"
raise ActionView::MissingTemplate.new(%w(foo), "foo/index", %w(foo), false, "mailer")
- when %r{/bad_request}
+ when "/bad_request"
raise ActionController::BadRequest
- when %r{/missing_keys}
+ when "/missing_keys"
raise ActionController::UrlGenerationError, "No route matches"
- when %r{/parameter_missing}
+ when "/parameter_missing"
raise ActionController::ParameterMissing, :missing_param_key
- when %r{/original_syntax_error}
+ when "/original_syntax_error"
eval "broke_syntax =" # `eval` need for raise native SyntaxError at runtime
- when %r{/syntax_error_into_view}
+ when "/syntax_error_into_view"
begin
eval "broke_syntax ="
rescue Exception
- template = ActionView::Template.new(File.read(__FILE__),
- __FILE__,
- ActionView::Template::Handlers::Raw.new,
- {})
raise ActionView::Template::Error.new(template)
end
- when %r{/framework_raises}
+ when "/framework_raises"
method_that_raises
- when %r{/nested_exceptions}
+ when "/nested_exceptions"
raise_nested_exceptions
else
raise "puke!"
diff --git a/actionpack/test/dispatch/live_response_test.rb b/actionpack/test/dispatch/live_response_test.rb
index a9a56f205f..b673fd3805 100644
--- a/actionpack/test/dispatch/live_response_test.rb
+++ b/actionpack/test/dispatch/live_response_test.rb
@@ -62,7 +62,7 @@ module ActionController
assert_nil @response.headers["Content-Length"]
end
- def test_headers_cannot_be_written_after_webserver_reads
+ def test_headers_cannot_be_written_after_web_server_reads
@response.stream.write "omg"
latch = Concurrent::CountDownLatch.new
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index 1f4e14aef6..f8d89def6a 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -284,7 +284,7 @@ module ActionDispatch
def test_generate_missing_keys_no_matches_different_format_keys
get "/:controller/:action/:name", to: "foo#bar"
- primarty_parameters = {
+ primary_parameters = {
id: 1,
controller: "tasks",
action: "show",
@@ -297,9 +297,9 @@ module ActionDispatch
missing_parameters = {
missing_key => "task_1"
}
- request_parameters = primarty_parameters.merge(redirection_parameters).merge(missing_parameters)
+ request_parameters = primary_parameters.merge(redirection_parameters).merge(missing_parameters)
- message = "No route matches #{Hash[request_parameters.sort_by { |k, v|k.to_s }].inspect}, missing required keys: #{[missing_key.to_sym].inspect}"
+ message = "No route matches #{Hash[request_parameters.sort_by { |k, _|k.to_s }].inspect}, missing required keys: #{[missing_key.to_sym].inspect}"
error = assert_raises(ActionController::UrlGenerationError) do
@formatter.generate(
diff --git a/actiontext/app/helpers/action_text/tag_helper.rb b/actiontext/app/helpers/action_text/tag_helper.rb
index 837b2264b1..8434f2c611 100644
--- a/actiontext/app/helpers/action_text/tag_helper.rb
+++ b/actiontext/app/helpers/action_text/tag_helper.rb
@@ -4,7 +4,7 @@ module ActionText
module TagHelper
cattr_accessor(:id, instance_accessor: false) { 0 }
- # Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as well as a hidden field
+ # Returns a +trix-editor+ tag that instantiates the Trix JavaScript editor as well as a hidden field
# that Trix will write to on changes, so the content will be sent on form submissions.
#
# ==== Options
@@ -50,7 +50,7 @@ module ActionView::Helpers
end
module FormHelper
- # Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as well as a hidden field
+ # Returns a +trix-editor+ tag that instantiates the Trix JavaScript editor as well as a hidden field
# that Trix will write to on changes, so the content will be sent on form submissions.
#
# ==== Options
diff --git a/actiontext/app/models/action_text/rich_text.rb b/actiontext/app/models/action_text/rich_text.rb
index 705dd30983..1f39bc51b9 100644
--- a/actiontext/app/models/action_text/rich_text.rb
+++ b/actiontext/app/models/action_text/rich_text.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
module ActionText
- # The RichText record holds the content produced by the Trix editor in a serialized `body` attribute.
+ # The RichText record holds the content produced by the Trix editor in a serialized +body+ attribute.
# It also holds all the references to the embedded files, which are stored using Active Storage.
# This record is then associated with the Active Record model the application desires to have
- # rich text content using the `has_rich_text` class method.
+ # rich text content using the +has_rich_text+ class method.
class RichText < ActiveRecord::Base
self.table_name = "action_text_rich_texts"
diff --git a/actiontext/app/views/active_storage/blobs/_blob.html.erb b/actiontext/app/views/active_storage/blobs/_blob.html.erb
index 049f57e804..49ba357dd1 100644
--- a/actiontext/app/views/active_storage/blobs/_blob.html.erb
+++ b/actiontext/app/views/active_storage/blobs/_blob.html.erb
@@ -1,6 +1,6 @@
<figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
<% if blob.representable? %>
- <%= image_tag blob.representation(resize_to_fit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
+ <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
<% end %>
<figcaption class="attachment__caption">
diff --git a/actiontext/test/dummy/config/puma.rb b/actiontext/test/dummy/config/puma.rb
index a5eccf816b..71ed69a895 100644
--- a/actiontext/test/dummy/config/puma.rb
+++ b/actiontext/test/dummy/config/puma.rb
@@ -16,7 +16,7 @@ port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the number of `workers` to boot in clustered mode.
-# Workers are forked webserver processes. If using threads and workers together
+# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb
index d41fe2a608..6cb342a0a9 100644
--- a/actionview/lib/action_view/base.rb
+++ b/actionview/lib/action_view/base.rb
@@ -10,6 +10,10 @@ require "action_view/template"
require "action_view/lookup_context"
module ActionView #:nodoc:
+ module CompiledTemplates #:nodoc:
+ # holds compiled template code
+ end
+
# = Action View Base
#
# Action View templates can be written in several ways.
@@ -141,6 +145,8 @@ module ActionView #:nodoc:
class Base
include Helpers, ::ERB::Util, Context
+ include CompiledTemplates
+
# Specify the proc used to decorate input tags that refer to attributes with errors.
cattr_accessor :field_error_proc, default: Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
@@ -210,6 +216,18 @@ module ActionView #:nodoc:
_prepare_context
end
+ def run(method, locals, buffer, &block)
+ _old_output_buffer, _old_virtual_path = @output_buffer, @virtual_path
+ @output_buffer = buffer
+ send(method, locals, buffer, &block)
+ ensure
+ @output_buffer, @virtual_path = _old_output_buffer, _old_virtual_path
+ end
+
+ def compiled_method_container
+ CompiledTemplates
+ end
+
ActiveSupport.run_load_hooks(:action_view, self)
end
end
diff --git a/actionview/lib/action_view/context.rb b/actionview/lib/action_view/context.rb
index 3c605c3ee3..2b22c30a3a 100644
--- a/actionview/lib/action_view/context.rb
+++ b/actionview/lib/action_view/context.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
module ActionView
- module CompiledTemplates #:nodoc:
- # holds compiled template code
- end
-
# = Action View Context
#
# Action View contexts are supplied to Action Controller to render a template.
@@ -16,7 +12,6 @@ module ActionView
# object that includes this module (although you can call _prepare_context
# defined below).
module Context
- include CompiledTemplates
attr_accessor :output_buffer, :view_flow
# Prepares the context by setting the appropriate instance variables.
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb
index c186cb8422..59d70a1dc4 100644
--- a/actionview/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb
@@ -329,14 +329,14 @@ module ActionView
# image_tag("pic.jpg", srcset: [["pic_1024.jpg", "1024w"], ["pic_1980.jpg", "1980w"]], sizes: "100vw")
# # => <img src="/assets/pic.jpg" srcset="/assets/pic_1024.jpg 1024w, /assets/pic_1980.jpg 1980w" sizes="100vw">
#
- # Active Storage (images that are uploaded by the users of your app):
+ # Active Storage blobs (images that are uploaded by the users of your app):
#
# image_tag(user.avatar)
# # => <img src="/rails/active_storage/blobs/.../tiger.jpg" />
- # image_tag(user.avatar.variant(resize_to_fit: [100, 100]))
- # # => <img src="/rails/active_storage/variants/.../tiger.jpg" />
- # image_tag(user.avatar.variant(resize_to_fit: [100, 100]), size: '100')
- # # => <img width="100" height="100" src="/rails/active_storage/variants/.../tiger.jpg" />
+ # image_tag(user.avatar.variant(resize_to_limit: [100, 100]))
+ # # => <img src="/rails/active_storage/representations/.../tiger.jpg" />
+ # image_tag(user.avatar.variant(resize_to_limit: [100, 100]), size: '100')
+ # # => <img width="100" height="100" src="/rails/active_storage/representations/.../tiger.jpg" />
def image_tag(source, options = {})
options = options.symbolize_keys
check_for_image_tag_errors(options)
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index cb850d75ee..f175c30aa1 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -363,7 +363,7 @@ module ActionView
@options = options
@block = block
- @locals = options[:locals] ? options[:locals].symbolize_keys : {}
+ @locals = options[:locals] || {}
@details = extract_details(options)
prepend_formats(options[:formats])
diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
index bb9db21e32..f414620923 100644
--- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb
+++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
@@ -43,14 +43,14 @@ module ActionView
# For streaming, instead of rendering a given a template, we return a Body
# object that responds to each. This object is initialized with a block
# that knows how to render the template.
- def render_template(template, layout_name = nil, locals = {}) #:nodoc:
+ def render_template(view, template, layout_name = nil, locals = {}) #:nodoc:
return [super] unless layout_name && template.supports_streaming?
locals ||= {}
layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
Body.new do |buffer|
- delayed_render(buffer, template, layout, @view, locals)
+ delayed_render(buffer, template, layout, view, locals)
end
end
diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
index ce8908924a..fb5539e0db 100644
--- a/actionview/lib/action_view/renderer/template_renderer.rb
+++ b/actionview/lib/action_view/renderer/template_renderer.rb
@@ -5,7 +5,6 @@ require "active_support/core_ext/object/try"
module ActionView
class TemplateRenderer < AbstractRenderer #:nodoc:
def render(context, options)
- @view = context
@details = extract_details(options)
template = determine_template(options)
@@ -13,7 +12,7 @@ module ActionView
@lookup_context.rendered_format ||= (template.formats.first || formats.first)
- render_template(template, options[:layout], options[:locals])
+ render_template(context, template, options[:layout], options[:locals])
end
private
@@ -46,22 +45,21 @@ module ActionView
# Renders the given template. A string representing the layout can be
# supplied as well.
- def render_template(template, layout_name = nil, locals = nil)
- view, locals = @view, locals || {}
+ def render_template(view, template, layout_name = nil, locals = nil)
+ locals ||= {}
- render_with_layout(layout_name, locals) do |layout|
+ render_with_layout(view, layout_name, locals) do |layout|
instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do
template.render(view, locals) { |*name| view._layout_for(*name) }
end
end
end
- def render_with_layout(path, locals)
+ def render_with_layout(view, path, locals)
layout = path && find_layout(path, locals.keys, [formats.first])
content = yield(layout)
if layout
- view = @view
view.view_flow.set(:layout, content)
layout.render(view, locals) { |*name| view._layout_for(*name) }
else
diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb
index cb4327cf16..205665a8c6 100644
--- a/actionview/lib/action_view/rendering.rb
+++ b/actionview/lib/action_view/rendering.rb
@@ -55,10 +55,8 @@ module ActionView
end
end
- attr_internal_writer :view_context_class
-
def view_context_class
- @_view_context_class ||= self.class.view_context_class
+ self.class.view_context_class
end
# An instance of a view class. The default view class is ActionView::Base.
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index 070d82cf17..8ce8053011 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -155,10 +155,10 @@ module ActionView
# This method is instrumented as "!render_template.action_view". Notice that
# we use a bang in this instrumentation because you don't want to
# consume this in production. This is only slow if it's being listened to.
- def render(view, locals, buffer = nil, &block)
+ def render(view, locals, buffer = ActionView::OutputBuffer.new, &block)
instrument_render_template do
compile!(view)
- view.send(method_name, locals, buffer, &block)
+ view.run(method_name, locals, buffer, &block)
end
rescue => e
handle_render_error(view, e)
@@ -264,11 +264,7 @@ module ActionView
# re-compilation
return if @compiled
- if view.is_a?(ActionView::CompiledTemplates)
- mod = ActionView::CompiledTemplates
- else
- mod = view.singleton_class
- end
+ mod = view.compiled_method_container
instrument("!compile_template") do
compile(mod)
@@ -301,9 +297,7 @@ module ActionView
# encoding of the code
source = +<<-end_src
def #{method_name}(local_assigns, output_buffer)
- _old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code}
- ensure
- @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
+ @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
end
end_src
diff --git a/actionview/lib/action_view/template/handlers/erb/erubi.rb b/actionview/lib/action_view/template/handlers/erb/erubi.rb
index db75f028ed..e155bae89d 100644
--- a/actionview/lib/action_view/template/handlers/erb/erubi.rb
+++ b/actionview/lib/action_view/template/handlers/erb/erubi.rb
@@ -13,7 +13,7 @@ module ActionView
# Dup properties so that we don't modify argument
properties = Hash[properties]
- properties[:preamble] = "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
+ properties[:preamble] = ""
properties[:postamble] = "@output_buffer.to_s"
properties[:bufvar] = "@output_buffer"
properties[:escapefunc] = ""
@@ -22,8 +22,12 @@ module ActionView
end
def evaluate(action_view_erb_handler_context)
- pr = eval("proc { #{@src} }", binding, @filename || "(erubi)")
- action_view_erb_handler_context.instance_eval(&pr)
+ src = @src
+ view = Class.new(ActionView::Base) {
+ include action_view_erb_handler_context._routes.url_helpers
+ class_eval("define_method(:_template) { |local_assigns, output_buffer| #{src} }", @filename || "(erubi)", 0)
+ }.new(action_view_erb_handler_context)
+ view.run(:_template, {}, ActionView::OutputBuffer.new)
end
private
diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb
index f90626ad9e..d71944e938 100644
--- a/actionview/test/abstract_unit.rb
+++ b/actionview/test/abstract_unit.rb
@@ -61,7 +61,7 @@ module RenderERBUtils
ActionView::Template::Handlers::ERB,
{})
- template.render(self, {}).strip
+ template.render(ActionView::Base.new, {}).strip
end
end
diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb
index 204903c60c..727d3fbc1a 100644
--- a/actionview/test/actionpack/controller/render_test.rb
+++ b/actionview/test/actionpack/controller/render_test.rb
@@ -485,8 +485,8 @@ class TestController < ActionController::Base
render partial: "customer", locals: { customer: Customer.new("david") }
end
- def partial_with_string_locals
- render partial: "customer", locals: { "customer" => Customer.new("david") }
+ def partial_with_hashlike_locals
+ render partial: "customer", locals: ActionController::Parameters.new(customer: Customer.new("david"))
end
def partial_with_form_builder
@@ -691,7 +691,7 @@ class RenderTest < ActionController::TestCase
get :partial_with_locals, to: "test#partial_with_locals"
get :partial_with_nested_object, to: "test#partial_with_nested_object"
get :partial_with_nested_object_shorthand, to: "test#partial_with_nested_object_shorthand"
- get :partial_with_string_locals, to: "test#partial_with_string_locals"
+ get :partial_with_hashlike_locals, to: "test#partial_with_hashlike_locals"
get :partials_list, to: "test#partials_list"
get :render_action_hello_world, to: "test#render_action_hello_world"
get :render_action_hello_world_as_string, to: "test#render_action_hello_world_as_string"
@@ -1292,8 +1292,8 @@ class RenderTest < ActionController::TestCase
assert_equal "Hello: david", @response.body
end
- def test_partial_with_string_locals
- get :partial_with_string_locals
+ def test_partial_with_hashlike_locals
+ get :partial_with_hashlike_locals
assert_equal "Hello: david", @response.body
end
diff --git a/actionview/test/template/template_test.rb b/actionview/test/template/template_test.rb
index b348d1f17b..8257d97b7c 100644
--- a/actionview/test/template/template_test.rb
+++ b/actionview/test/template/template_test.rb
@@ -18,7 +18,7 @@ class TestERBTemplate < ActiveSupport::TestCase
attr_accessor :formats
end
- class Context
+ class Context < ActionView::Base
def initialize
@output_buffer = "original"
@virtual_path = nil
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 571c050f2f..912b307683 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,31 @@
+* Fix year value when casting a multiparameter time hash
+
+ When assigning a hash to a time attribute that's missing a year component
+ (e.g. a `time_select` with `:ignore_date` set to `true`) then the year
+ defaults to 1970 instead of the expected 2000. This results in the attribute
+ changing as a result of the save.
+
+ Before:
+ ```
+ event = Event.new(start_time: { 4 => 20, 5 => 30 })
+ event.start_time # => 1970-01-01 20:30:00 UTC
+ event.save
+ event.reload
+ event.start_time # => 2000-01-01 20:30:00 UTC
+ ```
+
+ After:
+ ```
+ event = Event.new(start_time: { 4 => 20, 5 => 30 })
+ event.start_time # => 2000-01-01 20:30:00 UTC
+ event.save
+ event.reload
+ event.start_time # => 2000-01-01 20:30:00 UTC
+ ```
+
+ *Andrew White*
+
+
## Rails 6.0.0.beta1 (January 18, 2019) ##
* Add `ActiveModel::Errors#of_kind?`.
diff --git a/activemodel/lib/active_model/type/time.rb b/activemodel/lib/active_model/type/time.rb
index b3056b1333..8fba01b86a 100644
--- a/activemodel/lib/active_model/type/time.rb
+++ b/activemodel/lib/active_model/type/time.rb
@@ -5,7 +5,7 @@ module ActiveModel
class Time < Value # :nodoc:
include Helpers::TimeValue
include Helpers::AcceptsMultiparameterTime.new(
- defaults: { 1 => 1970, 2 => 1, 3 => 1, 4 => 0, 5 => 0 }
+ defaults: { 1 => 2000, 2 => 1, 3 => 1, 4 => 0, 5 => 0 }
)
def type
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index c5997283ea..9cb8b543b0 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -10,7 +10,6 @@ module ActiveModel
RESERVED_OPTIONS = CHECKS.keys + [:only_integer]
INTEGER_REGEX = /\A[+-]?\d+\z/
- DECIMAL_REGEX = /\A[+-]?\d+\.?\d*(e|e[+-])?\d+\z/
def check_validity!
keys = CHECKS.keys - [:odd, :even]
@@ -92,8 +91,8 @@ module ActiveModel
raw_value
elsif is_integer?(raw_value)
raw_value.to_i
- elsif is_decimal?(raw_value) && !is_hexadecimal_literal?(raw_value)
- BigDecimal(raw_value)
+ elsif !is_hexadecimal_literal?(raw_value)
+ Kernel.Float(raw_value).to_d
end
end
@@ -101,12 +100,8 @@ module ActiveModel
INTEGER_REGEX.match?(raw_value.to_s)
end
- def is_decimal?(raw_value)
- DECIMAL_REGEX.match?(raw_value.to_s)
- end
-
def is_hexadecimal_literal?(raw_value)
- /\A0[xX]/.match?(raw_value)
+ /\A0[xX]/.match?(raw_value.to_s)
end
def filtered_options(value)
diff --git a/activemodel/test/cases/type/time_test.rb b/activemodel/test/cases/type/time_test.rb
index 3fbae1a169..5c6271241d 100644
--- a/activemodel/test/cases/type/time_test.rb
+++ b/activemodel/test/cases/type/time_test.rb
@@ -16,6 +16,7 @@ module ActiveModel
assert_equal ::Time.utc(2000, 1, 1, 16, 45, 54), type.cast("2015-06-13T19:45:54+03:00")
assert_equal ::Time.utc(1999, 12, 31, 21, 7, 8), type.cast("06:07:08+09:00")
+ assert_equal ::Time.utc(2000, 1, 1, 16, 45, 54), type.cast(4 => 16, 5 => 45, 6 => 54)
end
def test_user_input_in_time_zone
diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb
index eb4b02df93..fcdf123062 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -281,6 +281,19 @@ class NumericalityValidationTest < ActiveModel::TestCase
assert_predicate topic, :invalid?
end
+ def test_validates_numericalty_with_object_acting_as_numeric
+ klass = Class.new do
+ def to_f
+ 123.54
+ end
+ end
+
+ Topic.validates_numericality_of :price
+ topic = Topic.new(price: klass.new)
+
+ assert_predicate topic, :valid?
+ end
+
def test_validates_numericality_with_invalid_args
assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, greater_than_or_equal_to: "foo" }
assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, less_than_or_equal_to: "foo" }
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 208c8c9c64..90a130320b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -134,7 +134,7 @@ module ActiveRecord
column_name = column_name.to_s
checks = []
checks << lambda { |c| c.name == column_name }
- checks << lambda { |c| c.type == type } if type
+ checks << lambda { |c| c.type == type.to_sym rescue nil } if type
column_options_keys.each do |attr|
checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 70d281b62b..5479ddab71 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -627,6 +627,7 @@ module ActiveRecord
ER_LOCK_WAIT_TIMEOUT = 1205
ER_QUERY_INTERRUPTED = 1317
ER_QUERY_TIMEOUT = 3024
+ ER_FK_INCOMPATIBLE_COLUMNS = 3780
def translate_exception(exception, message:, sql:, binds:)
case error_number(exception)
@@ -634,7 +635,7 @@ module ActiveRecord
RecordNotUnique.new(message, sql: sql, binds: binds)
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
InvalidForeignKey.new(message, sql: sql, binds: binds)
- when ER_CANNOT_ADD_FOREIGN
+ when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
mismatched_foreign_key(message, sql: sql, binds: binds)
when ER_CANNOT_CREATE_TABLE
if message.include?("errno: 150")
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb
index ceb8b40bd9..84dd28907b 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb
@@ -17,6 +17,42 @@ module ActiveRecord
"VALIDATE CONSTRAINT #{quote_column_name(name)}"
end
+ def visit_ChangeColumnDefinition(o)
+ column = o.column
+ column.sql_type = type_to_sql(column.type, column.options)
+ quoted_column_name = quote_column_name(o.name)
+
+ change_column_sql = +"ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}"
+
+ options = column_options(column)
+
+ if options[:collation]
+ change_column_sql << " COLLATE \"#{options[:collation]}\""
+ end
+
+ if options[:using]
+ change_column_sql << " USING #{options[:using]}"
+ elsif options[:cast_as]
+ cast_as_type = type_to_sql(options[:cast_as], options)
+ change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
+ end
+
+ if options.key?(:default)
+ if options[:default].nil?
+ change_column_sql << ", ALTER COLUMN #{quoted_column_name} DROP DEFAULT"
+ else
+ quoted_default = quote_default_expression(options[:default], column)
+ change_column_sql << ", ALTER COLUMN #{quoted_column_name} SET DEFAULT #{quoted_default}"
+ end
+ end
+
+ if options.key?(:null)
+ change_column_sql << ", ALTER COLUMN #{quoted_column_name} #{options[:null] ? 'DROP' : 'SET'} NOT NULL"
+ end
+
+ change_column_sql
+ end
+
def add_column_options!(sql, options)
if options[:collation]
sql << " COLLATE \"#{options[:collation]}\""
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index 3516bef75a..7cf371be68 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -683,38 +683,20 @@ module ActiveRecord
end
end
- def change_column_sql(table_name, column_name, type, options = {})
- quoted_column_name = quote_column_name(column_name)
- sql_type = type_to_sql(type, options)
- sql = +"ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}"
- if options[:collation]
- sql << " COLLATE \"#{options[:collation]}\""
- end
- if options[:using]
- sql << " USING #{options[:using]}"
- elsif options[:cast_as]
- cast_as_type = type_to_sql(options[:cast_as], options)
- sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
- end
-
- sql
- end
-
def add_column_for_alter(table_name, column_name, type, options = {})
return super unless options.key?(:comment)
[super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
end
def change_column_for_alter(table_name, column_name, type, options = {})
- sqls = [change_column_sql(table_name, column_name, type, options)]
- sqls << change_column_default_for_alter(table_name, column_name, options[:default]) if options.key?(:default)
- sqls << change_column_null_for_alter(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
+ td = create_table_definition(table_name)
+ cd = td.new_column_definition(column_name, type, options)
+ sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
sqls
end
- # Changes the default value of a table column.
- def change_column_default_for_alter(table_name, column_name, default_or_changes) # :nodoc:
+ def change_column_default_for_alter(table_name, column_name, default_or_changes)
column = column_for(table_name, column_name)
return unless column
@@ -729,8 +711,8 @@ module ActiveRecord
end
end
- def change_column_null_for_alter(table_name, column_name, null, default = nil) #:nodoc:
- "ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
+ def change_column_null_for_alter(table_name, column_name, null, default = nil)
+ "ALTER COLUMN #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
end
def add_timestamps_for_alter(table_name, options = {})
diff --git a/activerecord/lib/active_record/migration/compatibility.rb b/activerecord/lib/active_record/migration/compatibility.rb
index 8f6fcfcaea..608182e363 100644
--- a/activerecord/lib/active_record/migration/compatibility.rb
+++ b/activerecord/lib/active_record/migration/compatibility.rb
@@ -36,9 +36,7 @@ module ActiveRecord
class V5_1 < V5_2
def change_column(table_name, column_name, type, options = {})
if adapter_name == "PostgreSQL"
- clear_cache!
- sql = connection.send(:change_column_sql, table_name, column_name, type, options)
- execute "ALTER TABLE #{quote_table_name(table_name)} #{sql}"
+ super(table_name, column_name, type, options.except(:default, :null, :comment))
change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index c2b60610ce..2213fbefb4 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -436,7 +436,7 @@ module ActiveRecord
end
alias update_attributes update
- deprecate :update_attributes
+ deprecate update_attributes: "please, use update instead"
# Updates its receiver just like #update but calls #save! instead
# of +save+, so an exception is raised if the record is invalid and saving will fail.
@@ -450,7 +450,7 @@ module ActiveRecord
end
alias update_attributes! update!
- deprecate :update_attributes!
+ deprecate update_attributes!: "please, use update! instead"
# Equivalent to <code>update_columns(name => value)</code>.
def update_column(name, value)
diff --git a/activerecord/lib/active_record/relation/query_attribute.rb b/activerecord/lib/active_record/relation/query_attribute.rb
index 5e0b4ac160..1dd6462d8d 100644
--- a/activerecord/lib/active_record/relation/query_attribute.rb
+++ b/activerecord/lib/active_record/relation/query_attribute.rb
@@ -32,7 +32,7 @@ module ActiveRecord
if defined?(@_unboundable)
@_unboundable
else
- value_for_database
+ value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
@_unboundable = nil
end
rescue ::RangeError
diff --git a/activerecord/lib/arel/nodes/and.rb b/activerecord/lib/arel/nodes/and.rb
index c530a77bfb..bf516db35f 100644
--- a/activerecord/lib/arel/nodes/and.rb
+++ b/activerecord/lib/arel/nodes/and.rb
@@ -2,7 +2,7 @@
module Arel # :nodoc: all
module Nodes
- class And < Arel::Nodes::Node
+ class And < Arel::Nodes::NodeExpression
attr_reader :children
def initialize(children)
diff --git a/activerecord/lib/arel/nodes/case.rb b/activerecord/lib/arel/nodes/case.rb
index 654a54825e..1c4b727bf6 100644
--- a/activerecord/lib/arel/nodes/case.rb
+++ b/activerecord/lib/arel/nodes/case.rb
@@ -2,7 +2,7 @@
module Arel # :nodoc: all
module Nodes
- class Case < Arel::Nodes::Node
+ class Case < Arel::Nodes::NodeExpression
attr_accessor :case, :conditions, :default
def initialize(expression = nil, default = nil)
diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
index 2d71ee2f15..88c2ac5d0a 100644
--- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
@@ -139,8 +139,8 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
with_real_execute do
ActiveRecord::Base.connection.create_table :delete_me
ActiveRecord::Base.connection.add_timestamps :delete_me, null: true
- assert column_present?("delete_me", "updated_at", "datetime")
- assert column_present?("delete_me", "created_at", "datetime")
+ assert column_exists?("delete_me", "updated_at", "datetime")
+ assert column_exists?("delete_me", "created_at", "datetime")
ensure
ActiveRecord::Base.connection.drop_table :delete_me rescue nil
end
@@ -152,8 +152,8 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
t.timestamps null: true
end
ActiveRecord::Base.connection.remove_timestamps :delete_me, null: true
- assert_not column_present?("delete_me", "updated_at", "datetime")
- assert_not column_present?("delete_me", "created_at", "datetime")
+ assert_not column_exists?("delete_me", "updated_at", "datetime")
+ assert_not column_exists?("delete_me", "created_at", "datetime")
ensure
ActiveRecord::Base.connection.drop_table :delete_me rescue nil
end
@@ -194,9 +194,4 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
def method_missing(method_symbol, *arguments)
ActiveRecord::Base.connection.send(method_symbol, *arguments)
end
-
- def column_present?(table_name, column_name, type)
- results = ActiveRecord::Base.connection.select_all("SHOW FIELDS FROM #{table_name} LIKE '#{column_name}'")
- results.first && results.first["Type"] == type
- end
end
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index b12055a40a..2e7a4b498f 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -17,7 +17,7 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
enable_extension!("hstore", @connection)
@connection.transaction do
- @connection.create_table("pg_arrays") do |t|
+ @connection.create_table "pg_arrays", force: true do |t|
t.string "tags", array: true, limit: 255
t.integer "ratings", array: true
t.datetime :datetimes, array: true
@@ -112,6 +112,18 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
assert_predicate column, :array?
end
+ def test_change_column_from_non_array_to_array
+ @connection.add_column :pg_arrays, :snippets, :string
+ @connection.change_column :pg_arrays, :snippets, :text, array: true, default: [], using: "string_to_array(\"snippets\", ',')"
+
+ PgArray.reset_column_information
+ column = PgArray.columns_hash["snippets"]
+
+ assert_equal :text, column.type
+ assert_equal [], PgArray.column_defaults["snippets"]
+ assert_predicate column, :array?
+ end
+
def test_change_column_cant_make_non_array_column_to_array
@connection.add_column :pg_arrays, :a_string, :string
assert_raises ActiveRecord::StatementInvalid do
diff --git a/activerecord/test/cases/arel/nodes/and_test.rb b/activerecord/test/cases/arel/nodes/and_test.rb
index eff54abd91..d123ca9fd0 100644
--- a/activerecord/test/cases/arel/nodes/and_test.rb
+++ b/activerecord/test/cases/arel/nodes/and_test.rb
@@ -16,6 +16,15 @@ module Arel
assert_equal 2, array.uniq.size
end
end
+
+ describe "functions as node expression" do
+ it "allows aliasing" do
+ aliased = And.new(["foo", "bar"]).as("baz")
+
+ assert_kind_of As, aliased
+ assert_kind_of SqlLiteral, aliased.right
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/nodes/case_test.rb b/activerecord/test/cases/arel/nodes/case_test.rb
index 89861488df..946c2b0453 100644
--- a/activerecord/test/cases/arel/nodes/case_test.rb
+++ b/activerecord/test/cases/arel/nodes/case_test.rb
@@ -80,6 +80,16 @@ module Arel
assert_equal 2, array.uniq.size
end
end
+
+ describe "#as" do
+ it "allows aliasing" do
+ node = Case.new "foo"
+ as = node.as("bar")
+
+ assert_equal node, as.left
+ assert_kind_of Arel::Nodes::SqlLiteral, as.right
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/statement_cache_test.rb b/activerecord/test/cases/statement_cache_test.rb
index e3c12f68fd..6a6d73dc38 100644
--- a/activerecord/test/cases/statement_cache_test.rb
+++ b/activerecord/test/cases/statement_cache_test.rb
@@ -4,6 +4,7 @@ require "cases/helper"
require "models/book"
require "models/liquid"
require "models/molecule"
+require "models/numeric_data"
require "models/electron"
module ActiveRecord
@@ -74,6 +75,11 @@ module ActiveRecord
assert_equal "salty", liquids[0].name
end
+ def test_statement_cache_with_strictly_cast_attribute
+ row = NumericData.create(temperature: 1.5)
+ assert_equal row, NumericData.find_by(temperature: 1.5)
+ end
+
def test_statement_cache_values_differ
cache = ActiveRecord::StatementCache.create(Book.connection) do |params|
Book.where(name: "my book")
diff --git a/activerecord/test/cases/type/time_test.rb b/activerecord/test/cases/type/time_test.rb
new file mode 100644
index 0000000000..1a2c47479f
--- /dev/null
+++ b/activerecord/test/cases/type/time_test.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "models/topic"
+
+module ActiveRecord
+ module Type
+ class TimeTest < ActiveRecord::TestCase
+ def test_default_year_is_correct
+ expected_time = ::Time.utc(2000, 1, 1, 10, 30, 0)
+ topic = Topic.new(bonus_time: { 4 => 10, 5 => 30 })
+
+ assert_equal expected_time, topic.bonus_time
+
+ topic.save!
+ topic.reload
+
+ assert_equal expected_time, topic.bonus_time
+ end
+ end
+ end
+end
diff --git a/activestorage/README.md b/activestorage/README.md
index f658b8d542..2886169ca7 100644
--- a/activestorage/README.md
+++ b/activestorage/README.md
@@ -101,7 +101,7 @@ Variation of image attachment:
```erb
<%# Hitting the variant URL will lazy transform the original blob and then redirect to its new service location %>
-<%= image_tag user.avatar.variant(resize_to_fit: [100, 100]) %>
+<%= image_tag user.avatar.variant(resize_to_limit: [100, 100]) %>
```
## Direct uploads
diff --git a/activestorage/app/models/active_storage/blob/representable.rb b/activestorage/app/models/active_storage/blob/representable.rb
index 03d5511481..32e8fcefdf 100644
--- a/activestorage/app/models/active_storage/blob/representable.rb
+++ b/activestorage/app/models/active_storage/blob/representable.rb
@@ -10,7 +10,7 @@ module ActiveStorage::Blob::Representable
# Returns an ActiveStorage::Variant instance with the set of +transformations+ provided. This is only relevant for image
# files, and it allows any image to be transformed for size, colors, and the like. Example:
#
- # avatar.variant(resize_to_fit: [100, 100]).processed.service_url
+ # avatar.variant(resize_to_limit: [100, 100]).processed.service_url
#
# This will create and process a variant of the avatar blob that's constrained to a height and width of 100px.
# Then it'll upload said variant to the service according to a derivative key of the blob and the transformations.
@@ -18,7 +18,7 @@ module ActiveStorage::Blob::Representable
# Frequently, though, you don't actually want to transform the variant right away. But rather simply refer to a
# specific variant that can be created by a controller on-demand. Like so:
#
- # <%= image_tag Current.user.avatar.variant(resize_to_fit: [100, 100]) %>
+ # <%= image_tag Current.user.avatar.variant(resize_to_limit: [100, 100]) %>
#
# This will create a URL for that specific blob with that specific variant, which the ActiveStorage::RepresentationsController
# can then produce on-demand.
@@ -43,13 +43,13 @@ module ActiveStorage::Blob::Representable
# from a non-image blob. Active Storage comes with built-in previewers for videos and PDF documents. The video previewer
# extracts the first frame from a video and the PDF previewer extracts the first page from a PDF document.
#
- # blob.preview(resize_to_fit: [100, 100]).processed.service_url
+ # blob.preview(resize_to_limit: [100, 100]).processed.service_url
#
# Avoid processing previews synchronously in views. Instead, link to a controller action that processes them on demand.
# Active Storage provides one, but you may want to create your own (for example, if you need authentication). Here’s
# how to use the built-in version:
#
- # <%= image_tag video.preview(resize_to_fit: [100, 100]) %>
+ # <%= image_tag video.preview(resize_to_limit: [100, 100]) %>
#
# This method raises ActiveStorage::UnpreviewableError if no previewer accepts the receiving blob. To determine
# whether a blob is accepted by any previewer, call ActiveStorage::Blob#previewable?.
@@ -69,7 +69,7 @@ module ActiveStorage::Blob::Representable
# Returns an ActiveStorage::Preview for a previewable blob or an ActiveStorage::Variant for a variable image blob.
#
- # blob.representation(resize_to_fit: [100, 100]).processed.service_url
+ # blob.representation(resize_to_limit: [100, 100]).processed.service_url
#
# Raises ActiveStorage::UnrepresentableError if the receiving blob is neither variable nor previewable. Call
# ActiveStorage::Blob#representable? to determine whether a blob is representable.
diff --git a/activestorage/app/models/active_storage/preview.rb b/activestorage/app/models/active_storage/preview.rb
index dd50494799..bb9d960443 100644
--- a/activestorage/app/models/active_storage/preview.rb
+++ b/activestorage/app/models/active_storage/preview.rb
@@ -38,7 +38,7 @@ class ActiveStorage::Preview
# Processes the preview if it has not been processed yet. Returns the receiving Preview instance for convenience:
#
- # blob.preview(resize_to_fit: [100, 100]).processed.service_url
+ # blob.preview(resize_to_limit: [100, 100]).processed.service_url
#
# Processing a preview generates an image from its blob and attaches the preview image to the blob. Because the preview
# image is stored with the blob, it is only generated once.
diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb
index ea57fa5f78..bc0058967a 100644
--- a/activestorage/app/models/active_storage/variant.rb
+++ b/activestorage/app/models/active_storage/variant.rb
@@ -27,7 +27,7 @@ require "ostruct"
# To refer to such a delayed on-demand variant, simply link to the variant through the resolved route provided
# by Active Storage like so:
#
-# <%= image_tag Current.user.avatar.variant(resize_to_fit: [100, 100]) %>
+# <%= image_tag Current.user.avatar.variant(resize_to_limit: [100, 100]) %>
#
# This will create a URL for that specific blob with that specific variant, which the ActiveStorage::RepresentationsController
# can then produce on-demand.
@@ -36,15 +36,15 @@ require "ostruct"
# has already been processed and uploaded to the service, and, if so, just return that. Otherwise it will perform
# the transformations, upload the variant to the service, and return itself again. Example:
#
-# avatar.variant(resize_to_fit: [100, 100]).processed.service_url
+# avatar.variant(resize_to_limit: [100, 100]).processed.service_url
#
# This will create and process a variant of the avatar blob that's constrained to a height and width of 100.
# Then it'll upload said variant to the service according to a derivative key of the blob and the transformations.
#
# You can combine any number of ImageMagick/libvips operations into a variant, as well as any macros provided by the
-# ImageProcessing gem (such as +resize_to_fit+):
+# ImageProcessing gem (such as +resize_to_limit+):
#
-# avatar.variant(resize_to_fit: [800, 800], monochrome: true, rotate: "-90")
+# avatar.variant(resize_to_limit: [800, 800], monochrome: true, rotate: "-90")
#
# Visit the following links for a list of available ImageProcessing commands and ImageMagick/libvips operations:
#
diff --git a/activestorage/app/models/active_storage/variation.rb b/activestorage/app/models/active_storage/variation.rb
index 3adc2407e5..67568772da 100644
--- a/activestorage/app/models/active_storage/variation.rb
+++ b/activestorage/app/models/active_storage/variation.rb
@@ -6,7 +6,7 @@
# In case you do need to use this directly, it's instantiated using a hash of transformations where
# the key is the command and the value is the arguments. Example:
#
-# ActiveStorage::Variation.new(resize_to_fit: [100, 100], monochrome: true, trim: true, rotate: "-90")
+# ActiveStorage::Variation.new(resize_to_limit: [100, 100], monochrome: true, trim: true, rotate: "-90")
#
# The options map directly to {ImageProcessing}[https://github.com/janko-m/image_processing] commands.
class ActiveStorage::Variation
diff --git a/activestorage/test/controllers/blobs_controller_test.rb b/activestorage/test/controllers/blobs_controller_test.rb
index 9c811df895..9bf2641de6 100644
--- a/activestorage/test/controllers/blobs_controller_test.rb
+++ b/activestorage/test/controllers/blobs_controller_test.rb
@@ -20,3 +20,28 @@ class ActiveStorage::BlobsControllerTest < ActionDispatch::IntegrationTest
assert_equal "max-age=300, private", @response.headers["Cache-Control"]
end
end
+
+if SERVICE_CONFIGURATIONS[:s3] && SERVICE_CONFIGURATIONS[:s3][:access_key_id].present?
+ class ActiveStorage::S3BlobsControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ @old_service = ActiveStorage::Blob.service
+ ActiveStorage::Blob.service = ActiveStorage::Service.configure(:s3, SERVICE_CONFIGURATIONS)
+ end
+
+ teardown do
+ ActiveStorage::Blob.service = @old_service
+ end
+
+ test "allow redirection to the different host" do
+ blob = create_file_blob filename: "racecar.jpg"
+
+ assert_nothing_raised { get rails_blob_url(blob) }
+ assert_response :redirect
+ assert_no_match @request.host, @response.headers["Location"]
+ ensure
+ blob.purge
+ end
+ end
+else
+ puts "Skipping S3 redirection tests because no S3 configuration was supplied"
+end
diff --git a/activestorage/test/controllers/representations_controller_test.rb b/activestorage/test/controllers/representations_controller_test.rb
index 2662cc5283..4ae0ff877e 100644
--- a/activestorage/test/controllers/representations_controller_test.rb
+++ b/activestorage/test/controllers/representations_controller_test.rb
@@ -59,3 +59,33 @@ class ActiveStorage::RepresentationsControllerWithPreviewsTest < ActionDispatch:
assert_response :not_found
end
end
+
+if SERVICE_CONFIGURATIONS[:s3] && SERVICE_CONFIGURATIONS[:s3][:access_key_id].present?
+ class ActiveStorage::S3RepresentationsControllerWithVariantsTest < ActionDispatch::IntegrationTest
+ setup do
+ @old_service = ActiveStorage::Blob.service
+ ActiveStorage::Blob.service = ActiveStorage::Service.configure(:s3, SERVICE_CONFIGURATIONS)
+ end
+
+ teardown do
+ ActiveStorage::Blob.service = @old_service
+ end
+
+ test "allow redirection to the different host" do
+ blob = create_file_blob filename: "racecar.jpg"
+
+ assert_nothing_raised do
+ get rails_blob_representation_url(
+ filename: blob.filename,
+ signed_blob_id: blob.signed_id,
+ variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
+ end
+ assert_response :redirect
+ assert_no_match @request.host, @response.headers["Location"]
+ ensure
+ blob.purge
+ end
+ end
+else
+ puts "Skipping S3 redirection tests because no S3 configuration was supplied"
+end
diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md
index 5a97fbb586..6432dbfd00 100644
--- a/guides/CHANGELOG.md
+++ b/guides/CHANGELOG.md
@@ -1,5 +1,13 @@
## Rails 6.0.0.beta1 (January 18, 2019) ##
+* Add "Action Text Overview" Guide.
+
+ *DHH*
+
+* Add "Action Mailbox Basics" Guide.
+
+ *DHH*
+
* New section _Troubleshooting_ in the _Autoloading and Reloading Constants_ guide.
*Xavier Noria*
diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md
index 474a93c83e..e3bb41ae32 100644
--- a/guides/source/active_storage_overview.md
+++ b/guides/source/active_storage_overview.md
@@ -434,7 +434,7 @@ original blob into the specified format and redirect to its new service
location.
```erb
-<%= image_tag user.avatar.variant(resize_to_fit: [100, 100]) %>
+<%= image_tag user.avatar.variant(resize_to_limit: [100, 100]) %>
```
To switch to the Vips processor, you would add the following to
diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md
index 3ac3f8fa8b..56c0ca78a0 100644
--- a/guides/source/caching_with_rails.md
+++ b/guides/source/caching_with_rails.md
@@ -51,10 +51,10 @@ For instance, it will not impact low-level caching, that we address
### Page Caching
Page caching is a Rails mechanism which allows the request for a generated page
-to be fulfilled by the webserver (i.e. Apache or NGINX) without having to go
+to be fulfilled by the web server (i.e. Apache or NGINX) without having to go
through the entire Rails stack. While this is super fast it can't be applied to
every situation (such as pages that need authentication). Also, because the
-webserver is serving a file directly from the filesystem you will need to
+web server is serving a file directly from the filesystem you will need to
implement cache expiration.
INFO: Page Caching has been removed from Rails 4. See the [actionpack-page_caching gem](https://github.com/rails/actionpack-page_caching).
diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md
index b3baf726e3..e84e5561f2 100644
--- a/guides/source/development_dependencies_install.md
+++ b/guides/source/development_dependencies_install.md
@@ -227,7 +227,6 @@ If you're using another database, check the file `activerecord/test/config.yml`
If you installed Yarn, you will need to install the javascript dependencies:
```bash
-$ cd activestorage
$ yarn install
```
diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md
index c33851a0f9..69b5f254bf 100644
--- a/guides/source/rails_on_rack.md
+++ b/guides/source/rails_on_rack.md
@@ -35,7 +35,7 @@ application. Any Rack compliant web server should be using
### `rails server`
-`rails server` does the basic job of creating a `Rack::Server` object and starting the webserver.
+`rails server` does the basic job of creating a `Rack::Server` object and starting the web server.
Here's how `rails server` creates an instance of `Rack::Server`
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 1a2f480407..61353e8e7d 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -1775,7 +1775,7 @@ test "connects with cookies" do
end
```
-See the API documentation for [`AcionCable::Connection::TestCase`](http://api.rubyonrails.org/classes/ActionCable/Connection/TestCase.html) for more information.
+See the API documentation for [`ActionCable::Connection::TestCase`](http://api.rubyonrails.org/classes/ActionCable/Connection/TestCase.html) for more information.
### Channel Test Case
@@ -1806,11 +1806,11 @@ require "test_helper"
class WebNotificationsChannelTest < ActionCable::Channel::TestCase
test "subscribes and stream for user" do
- stub_connection current_user: users[:john]
+ stub_connection current_user: users(:john)
subscribe
- assert_has_stream_for users[:john]
+ assert_has_stream_for users(:john)
end
end
```
@@ -1837,6 +1837,33 @@ class ProductTest < ActionCable::TestCase
end
```
+If you want to test the broadcasting made with `Channel.broadcast_to`, you shoud use
+`Channel.broadcasting_for` to generate an underlying stream name:
+
+```ruby
+# app/jobs/chat_relay_job.rb
+class ChatRelayJob < ApplicationJob
+ def perform_later(room, message)
+ ChatChannel.broadcast_to room, text: message
+ end
+end
+
+# test/jobs/chat_relay_job_test.rb
+require 'test_helper'
+
+class ChatRelayJobTest < ActiveJob::TestCase
+ include ActionCable::TestHelper
+
+ test "broadcast message to room" do
+ room = rooms(:all)
+
+ assert_broadcast_on(ChatChannel.broadcasting_for(room), text: "Hi!") do
+ ChatRelayJob.perform_now(room, "Hi!")
+ end
+ end
+end
+```
+
Additional Testing Resources
----------------------------
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 5b249de47e..e55217c5c4 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Fix deeply nested namespace command printing.
+
+ *Gannon McGibbon*
+
+
## Rails 6.0.0.beta1 (January 18, 2019) ##
* Remove deprecated `after_bundle` helper inside plugins templates.
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index d5a66b6ec1..b7838f7e32 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -30,7 +30,7 @@ module Rails
@filter_parameters = []
@filter_redirect = []
@helpers_paths = []
- @hosts = Array(([IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0"), "localhost"] if Rails.env.development?))
+ @hosts = Array(([IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0"), ".localhost"] if Rails.env.development?))
@public_file_server = ActiveSupport::OrderedOptions.new
@public_file_server.enabled = true
@public_file_server.index_name = "index"
diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb
index 766872de8a..a22b198c66 100644
--- a/railties/lib/rails/command/base.rb
+++ b/railties/lib/rails/command/base.rb
@@ -115,7 +115,7 @@ module Rails
# For a Rails::Command::TestCommand placed in <tt>rails/command/test_command.rb</tt>
# would return <tt>rails/test</tt>.
def default_command_root
- path = File.expand_path(File.join("../commands", command_root_namespace), __dir__)
+ path = File.expand_path(relative_command_path, __dir__)
path if File.exist?(path)
end
@@ -135,12 +135,20 @@ module Rails
end
def command_root_namespace
- (namespace.split(":") - %w( rails )).first
+ (namespace.split(":") - %w(rails)).join(":")
+ end
+
+ def relative_command_path
+ File.join("../commands", *command_root_namespace.split(":"))
end
def namespaced_commands
commands.keys.map do |key|
- key == command_root_namespace ? key : "#{command_root_namespace}:#{key}"
+ if command_root_namespace.match?(/(\A|\:)#{key}\z/)
+ command_root_namespace
+ else
+ "#{command_root_namespace}:#{key}"
+ end
end
end
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 0023a9a6a6..0eed552042 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -128,7 +128,7 @@ module Rails
def gemfile_entries # :doc:
[rails_gemfile_entry,
database_gemfile_entry,
- webserver_gemfile_entry,
+ web_server_gemfile_entry,
assets_gemfile_entry,
webpacker_gemfile_entry,
javascript_gemfile_entry,
@@ -189,7 +189,7 @@ module Rails
"Use #{options[:database]} as the database for Active Record"
end
- def webserver_gemfile_entry # :doc:
+ def web_server_gemfile_entry # :doc:
return [] if options[:skip_puma]
comment = "Use Puma as the app server"
GemfileEntry.new("puma", "~> 3.11", comment)
diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt
index f6146e7259..649253aeca 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt
@@ -17,7 +17,7 @@ port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the number of `workers` to boot in clustered mode.
-# Workers are forked webserver processes. If using threads and workers together
+# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake
index 8cacf4a49f..5abba7d3b4 100644
--- a/railties/lib/rails/tasks/statistics.rake
+++ b/railties/lib/rails/tasks/statistics.rake
@@ -9,6 +9,7 @@ STATS_DIRECTORIES = [
%w(Jobs app/jobs),
%w(Models app/models),
%w(Mailers app/mailers),
+ %w(Mailboxes app/mailboxes),
%w(Channels app/channels),
%w(JavaScripts app/assets/javascripts),
%w(JavaScript app/javascript),
@@ -18,6 +19,8 @@ STATS_DIRECTORIES = [
%w(Helper\ tests test/helpers),
%w(Model\ tests test/models),
%w(Mailer\ tests test/mailers),
+ %w(Mailbox\ tests test/mailboxes),
+ %w(Channel\ tests test/channels),
%w(Job\ tests test/jobs),
%w(Integration\ tests test/integration),
%w(System\ tests test/system),
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 3e979ea20d..9da3956dda 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -2289,6 +2289,11 @@ module ApplicationTests
MESSAGE
end
+ test "the host whitelist includes .localhost in development" do
+ app "development"
+ assert_includes Rails.application.config.hosts, ".localhost"
+ end
+
private
def force_lazy_load_hooks
yield # Tasty clarifying sugar, homie! We only need to reference a constant to load it.
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index 830c36671c..44e3b0f66b 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -118,7 +118,7 @@ module ApplicationTests
end
def test_code_statistics_sanity
- assert_match "Code LOC: 29 Test LOC: 0 Code to Test Ratio: 1:0.0",
+ assert_match "Code LOC: 32 Test LOC: 0 Code to Test Ratio: 1:0.0",
rails("stats")
end
diff --git a/railties/test/command/base_test.rb b/railties/test/command/base_test.rb
index a49ae8aae7..9132c8b4af 100644
--- a/railties/test/command/base_test.rb
+++ b/railties/test/command/base_test.rb
@@ -4,10 +4,12 @@ require "abstract_unit"
require "rails/command"
require "rails/commands/generate/generate_command"
require "rails/commands/secrets/secrets_command"
+require "rails/commands/db/system/change/change_command"
class Rails::Command::BaseTest < ActiveSupport::TestCase
test "printing commands" do
assert_equal %w(generate), Rails::Command::GenerateCommand.printing_commands
assert_equal %w(secrets:setup secrets:edit secrets:show), Rails::Command::SecretsCommand.printing_commands
+ assert_equal %w(db:system:change), Rails::Command::Db::System::ChangeCommand.printing_commands
end
end
diff --git a/tasks/release.rb b/tasks/release.rb
index 6784330fd6..2fdcea9d12 100644
--- a/tasks/release.rb
+++ b/tasks/release.rb
@@ -218,7 +218,7 @@ namespace :all do
<p>
<% if @user.avatar.attached? -%>
- <%= image_tag @user.avatar.representation(resize_to_fit: [500, 500]) %>
+ <%= image_tag @user.avatar.representation(resize_to_limit: [500, 500]) %>
<% end -%>
</p>
CODE