diff options
162 files changed, 2049 insertions, 806 deletions
@@ -29,7 +29,7 @@ group :doc do gem 'sdoc', '~> 0.4.0' gem 'redcarpet', '~> 3.2.2', platforms: :ruby gem 'w3c_validators' - gem 'kindlerb' + gem 'kindlerb', '0.1.1' end # AS diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index 008760f2fc..86ecb3ee88 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -1,5 +1,7 @@ * Add `assert_enqueued_emails` and `assert_no_enqueued_emails`. + Example: + def test_emails assert_enqueued_emails 2 do ContactMailer.welcome.deliver_later diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index d545c59afc..5e0c64900f 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,28 @@ +* Migrating to keyword arguments syntax in `ActionController::TestCase` and + `ActionDispatch::Integration` HTTP request methods. + + Example: + + post :create, params: { y: x }, session: { a: 'b' } + get :view, params: { id: 1 } + get :view, params: { id: 1 }, format: :json + + *Kir Shatrov* + +* Preserve default url options when generating URLs. + + Fixes an issue that would cause default_url_options to be lost when + generating URLs with fewer positional arguments than parameters in the + route definition. + + *Tekin Suleyman* + +* Deprecate *_via_redirect integration test methods. + + Use `follow_redirect!` manually after the request call for the same behavior. + + *Aditya Kapoor* + * Add `ActionController::Renderer` to render arbitrary templates outside controller actions. @@ -22,6 +47,7 @@ * Allow you to pass `prepend: false` to protect_from_forgery to have the verification callback appended instead of prepended to the chain. This allows you to let the verification step depend on prior callbacks. + Example: class ApplicationController < ActionController::Base @@ -118,7 +144,7 @@ *Travis Grathwell* -* Stop converting empty arrays in `params` to `nil` +* Stop converting empty arrays in `params` to `nil`. This behaviour was introduced in response to CVE-2012-2660, CVE-2012-2694 and CVE-2013-0155 diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index db999c2765..69f490b327 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -69,7 +69,7 @@ module AbstractController end def skip_filter(*names) - ActiveSupport::Deprecation.warn("#{callback}_filter is deprecated and will removed in Rails 5.1. Use #{callback}_action instead.") + ActiveSupport::Deprecation.warn("#{callback}_filter is deprecated and will be removed in Rails 5.1. Use #{callback}_action instead.") skip_action_callback(*names) end @@ -188,7 +188,7 @@ module AbstractController end define_method "#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("#{callback}_filter is deprecated and will removed in Rails 5.1. Use #{callback}_action instead.") + ActiveSupport::Deprecation.warn("#{callback}_filter is deprecated and will be removed in Rails 5.1. Use #{callback}_action instead.") send("#{callback}_action", *names, &blk) end @@ -199,7 +199,7 @@ module AbstractController end define_method "prepend_#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("prepend_#{callback}_filter is deprecated and will removed in Rails 5.1. Use prepend_#{callback}_action instead.") + ActiveSupport::Deprecation.warn("prepend_#{callback}_filter is deprecated and will be removed in Rails 5.1. Use prepend_#{callback}_action instead.") send("prepend_#{callback}_action", *names, &blk) end @@ -212,7 +212,7 @@ module AbstractController end define_method "skip_#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("skip_#{callback}_filter is deprecated and will removed in Rails 5.1. Use skip_#{callback}_action instead.") + ActiveSupport::Deprecation.warn("skip_#{callback}_filter is deprecated and will be removed in Rails 5.1. Use skip_#{callback}_action instead.") send("skip_#{callback}_action", *names, &blk) end @@ -220,7 +220,7 @@ module AbstractController alias_method :"append_#{callback}_action", :"#{callback}_action" define_method "append_#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("append_#{callback}_filter is deprecated and will removed in Rails 5.1. Use append_#{callback}_action instead.") + ActiveSupport::Deprecation.warn("append_#{callback}_filter is deprecated and will be removed in Rails 5.1. Use append_#{callback}_action instead.") send("append_#{callback}_action", *names, &blk) end end diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index d30615fade..afe95e3fec 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -494,55 +494,61 @@ module ActionController # Simulate a GET request with the given parameters. # # - +action+: The controller action to call. - # - +parameters+: The HTTP parameters that you want to pass. This may - # be +nil+, a hash, or a string that is appropriately encoded + # - +params+: The hash with HTTP parameters that you want to pass. This may be +nil+. + # - +body+: The request body with a string that is appropriately encoded # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>). # - +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+. # # You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with # +post+, +patch+, +put+, +delete+, and +head+. + # Example sending parameters, session and setting a flash message: + # + # get :show, + # params: { id: 7 }, + # session: { user_id: 1 }, + # flash: { notice: 'This is flash message' } # # Note that the request method is not verified. The different methods are # available to make the tests more expressive. def get(action, *args) - process(action, "GET", *args) + process_with_kwargs("GET", action, *args) end # Simulate a POST request with the given parameters and set/volley the response. # See +get+ for more details. def post(action, *args) - process(action, "POST", *args) + process_with_kwargs("POST", action, *args) end # Simulate a PATCH request with the given parameters and set/volley the response. # See +get+ for more details. def patch(action, *args) - process(action, "PATCH", *args) + process_with_kwargs("PATCH", action, *args) end # Simulate a PUT request with the given parameters and set/volley the response. # See +get+ for more details. def put(action, *args) - process(action, "PUT", *args) + process_with_kwargs("PUT", action, *args) end # Simulate a DELETE request with the given parameters and set/volley the response. # See +get+ for more details. def delete(action, *args) - process(action, "DELETE", *args) + process_with_kwargs("DELETE", action, *args) end # Simulate a HEAD request with the given parameters and set/volley the response. # See +get+ for more details. def head(action, *args) - process(action, "HEAD", *args) + process_with_kwargs("HEAD", action, *args) end - def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) + def xml_http_request(*args) @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' @request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') - __send__(request_method, action, parameters, session, flash).tap do + __send__(*args).tap do @request.env.delete 'HTTP_X_REQUESTED_WITH' @request.env.delete 'HTTP_ACCEPT' end @@ -566,41 +572,69 @@ module ActionController # parameters and set/volley the response. # # - +action+: The controller action to call. - # - +http_method+: Request method used to send the http request. Possible values - # are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+. - # - +parameters+: The HTTP parameters. This may be +nil+, a hash, or a - # string that is appropriately encoded (+application/x-www-form-urlencoded+ - # or +multipart/form-data+). + # - +method+: Request method used to send the HTTP request. Possible values + # are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+. Can be a symbol. + # - +params+: The hash with HTTP parameters that you want to pass. This may be +nil+. + # - +body+: The request body with a string that is appropriately encoded + # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>). # - +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. # # Example calling +create+ action and sending two params: # - # process :create, 'POST', user: { name: 'Gaurish Sharma', email: 'user@example.com' } - # - # Example sending parameters, +nil+ session and setting a flash message: - # - # process :view, 'GET', { id: 7 }, nil, { notice: 'This is flash message' } + # process :create, + # method: 'POST', + # params: { + # user: { name: 'Gaurish Sharma', email: 'user@example.com' } + # }, + # session: { user_id: 1 }, + # flash: { notice: 'This is flash message' } # # To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+ and +HEAD+ requests # prefer using #get, #post, #patch, #put, #delete and #head methods # respectively which will make tests more expressive. # # Note that the request method is not verified. - def process(action, http_method = 'GET', *args) + def process(action, *args) check_required_ivars - if args.first.is_a?(String) && http_method != 'HEAD' - @request.env['RAW_POST_DATA'] = args.shift + if kwarg_request?(*args) + parameters, session, body, flash, http_method, format = args[0].values_at(:params, :session, :body, :flash, :method, :format) + else + http_method, parameters, session, flash = args + format = nil + + if parameters.is_a?(String) && http_method != 'HEAD' + body = parameters + parameters = nil + end + + if parameters.present? || session.present? || flash.present? + non_kwarg_request_warning + end + end + + if body.present? + @request.env['RAW_POST_DATA'] = body + end + + if http_method.present? + http_method = http_method.to_s.upcase + else + http_method = "GET" end - parameters, session, flash = args parameters ||= {} # Ensure that numbers and symbols passed as params are converted to # proper params, as is the case when engaging rack. parameters = paramify_values(parameters) if html_format?(parameters) + if format.present? + parameters[:format] = format + end + @html_document = nil unless @controller.respond_to?(:recycle!) @@ -693,6 +727,38 @@ module ActionController private + def process_with_kwargs(http_method, action, *args) + if kwarg_request?(*args) + args.first.merge!(method: http_method) + process(action, *args) + else + non_kwarg_request_warning if args.present? + + args = args.unshift(http_method) + process(action, *args) + end + end + + REQUEST_KWARGS = %i(params session flash method body) + def kwarg_request?(*args) + args[0].respond_to?(:keys) && ( + (args[0].key?(:format) && args[0].keys.size == 1) || + args[0].keys.any? { |k| REQUEST_KWARGS.include?(k) } + ) + end + + def non_kwarg_request_warning + ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc) + ActionController::TestCase HTTP request methods will accept only + keyword arguments in future Rails versions. + + Examples: + + get :show, params: { id: 1 }, session: { user_id: 1 } + process :update, method: :post, params: { id: 1 } + MSG + end + def document_root_element html_document.root end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 7d8863dfe5..2b24b896db 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -264,9 +264,10 @@ module ActionDispatch path_params -= controller_options.keys path_params -= result.keys end - path_params.each { |param| - result[param] = inner_options.fetch(param) { args.shift } - } + path_params -= inner_options.keys + path_params.take(args.size).each do |param| + result[param] = args.shift + end end result.merge!(inner_options) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index f0e2c5becc..db6233840a 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -12,12 +12,14 @@ module ActionDispatch # # - +path+: The URI (as a String) on which you want to perform a GET # request. - # - +parameters+: The HTTP parameters that you want to pass. This may + # - +params+: The HTTP parameters that you want to pass. This may # be +nil+, # a Hash, or a String that is appropriately encoded # (<tt>application/x-www-form-urlencoded</tt> or # <tt>multipart/form-data</tt>). - # - +headers_or_env+: Additional headers to pass, as a Hash. The headers will be + # - +headers+: Additional headers to pass, as a Hash. The headers will be + # merged into the Rack env hash. + # - +env+: Additional env to pass, as a Hash. The headers will be # merged into the Rack env hash. # # This method returns a Response object, which one can use to @@ -28,38 +30,43 @@ module ActionDispatch # # You can also perform POST, PATCH, PUT, DELETE, and HEAD requests with # +#post+, +#patch+, +#put+, +#delete+, and +#head+. - def get(path, parameters = nil, headers_or_env = nil) - process :get, path, parameters, headers_or_env + # + # Example: + # + # get '/feed', params: { since: 201501011400 } + # post '/profile', headers: { "X-Test-Header" => "testvalue" } + def get(path, *args) + process_with_kwargs(:get, path, *args) end # Performs a POST request with the given parameters. See +#get+ for more # details. - def post(path, parameters = nil, headers_or_env = nil) - process :post, path, parameters, headers_or_env + def post(path, *args) + process_with_kwargs(:post, path, *args) end # Performs a PATCH request with the given parameters. See +#get+ for more # details. - def patch(path, parameters = nil, headers_or_env = nil) - process :patch, path, parameters, headers_or_env + def patch(path, *args) + process_with_kwargs(:patch, path, *args) end # Performs a PUT request with the given parameters. See +#get+ for more # details. - def put(path, parameters = nil, headers_or_env = nil) - process :put, path, parameters, headers_or_env + def put(path, *args) + process_with_kwargs(:put, path, *args) end # Performs a DELETE request with the given parameters. See +#get+ for # more details. - def delete(path, parameters = nil, headers_or_env = nil) - process :delete, path, parameters, headers_or_env + def delete(path, *args) + process_with_kwargs(:delete, path, *args) end # Performs a HEAD request with the given parameters. See +#get+ for more # details. - def head(path, parameters = nil, headers_or_env = nil) - process :head, path, parameters, headers_or_env + def head(path, *args) + process_with_kwargs(:head, path, *args) end # Performs an XMLHttpRequest request with the given parameters, mirroring @@ -68,11 +75,28 @@ module ActionDispatch # The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or # +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart # string; the headers are a hash. - def xml_http_request(request_method, path, parameters = nil, headers_or_env = nil) - headers_or_env ||= {} - headers_or_env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' - headers_or_env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') - process(request_method, path, parameters, headers_or_env) + # + # Example: + # + # xhr :get, '/feed', params: { since: 201501011400 } + def xml_http_request(request_method, path, *args) + if kwarg_request?(*args) + params, headers, env = args.first.values_at(:params, :headers, :env) + else + params = args[0] + headers = args[1] + env = {} + + if params.present? || headers.present? + non_kwarg_request_warning + end + end + + headers ||= {} + headers.merge!(env) if env + headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' + headers['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') + process(request_method, path, params: params, headers: headers) end alias xhr :xml_http_request @@ -89,40 +113,52 @@ module ActionDispatch # redirect. Note that the redirects are followed until the response is # not a redirect--this means you may run into an infinite loop if your # redirect loops back to itself. - def request_via_redirect(http_method, path, parameters = nil, headers_or_env = nil) - process(http_method, path, parameters, headers_or_env) + # + # Example: + # + # request_via_redirect :post, '/welcome', + # params: { ref_id: 14 }, + # headers: { "X-Test-Header" => "testvalue" } + def request_via_redirect(http_method, path, *args) + process_with_kwargs(http_method, path, *args) + follow_redirect! while redirect? status end # Performs a GET request, following any subsequent redirect. # See +request_via_redirect+ for more information. - def get_via_redirect(path, parameters = nil, headers_or_env = nil) - request_via_redirect(:get, path, parameters, headers_or_env) + def get_via_redirect(path, *args) + ActiveSupport::Deprecation.warn('`get_via_redirect` is deprecated and will be removed in the next version of Rails. Please use follow_redirect! manually after the request call for the same behavior.') + request_via_redirect(:get, path, *args) end # Performs a POST request, following any subsequent redirect. # See +request_via_redirect+ for more information. - def post_via_redirect(path, parameters = nil, headers_or_env = nil) - request_via_redirect(:post, path, parameters, headers_or_env) + def post_via_redirect(path, *args) + ActiveSupport::Deprecation.warn('`post_via_redirect` is deprecated and will be removed in the next version of Rails. Please use follow_redirect! manually after the request call for the same behavior.') + request_via_redirect(:post, path, *args) end # Performs a PATCH request, following any subsequent redirect. # See +request_via_redirect+ for more information. - def patch_via_redirect(path, parameters = nil, headers_or_env = nil) - request_via_redirect(:patch, path, parameters, headers_or_env) + def patch_via_redirect(path, *args) + ActiveSupport::Deprecation.warn('`patch_via_redirect` is deprecated and will be removed in the next version of Rails. Please use follow_redirect! manually after the request call for the same behavior.') + request_via_redirect(:patch, path, *args) end # Performs a PUT request, following any subsequent redirect. # See +request_via_redirect+ for more information. - def put_via_redirect(path, parameters = nil, headers_or_env = nil) - request_via_redirect(:put, path, parameters, headers_or_env) + def put_via_redirect(path, *args) + ActiveSupport::Deprecation.warn('`put_via_redirect` is deprecated and will be removed in the next version of Rails. Please use follow_redirect! manually after the request call for the same behavior.') + request_via_redirect(:put, path, *args) end # Performs a DELETE request, following any subsequent redirect. # See +request_via_redirect+ for more information. - def delete_via_redirect(path, parameters = nil, headers_or_env = nil) - request_via_redirect(:delete, path, parameters, headers_or_env) + def delete_via_redirect(path, *args) + ActiveSupport::Deprecation.warn('`delete_via_redirect` is deprecated and will be removed in the next version of Rails. Please use follow_redirect! manually after the request call for the same behavior.') + request_via_redirect(:delete, path, *args) end end @@ -261,8 +297,39 @@ module ActionDispatch @_mock_session ||= Rack::MockSession.new(@app, host) end + def process_with_kwargs(http_method, path, *args) + if kwarg_request?(*args) + process(http_method, path, *args) + else + non_kwarg_request_warning if args.present? + process(http_method, path, { params: args[0], headers: args[1] }) + end + end + + REQUEST_KWARGS = %i(params headers env) + def kwarg_request?(*args) + args[0].respond_to?(:keys) && args[0].keys.any? { |k| REQUEST_KWARGS.include?(k) } + end + + def non_kwarg_request_warning + ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc) + ActionDispatch::Integration::TestCase HTTP request methods will accept only + keyword arguments in future Rails versions. + + Examples: + + get '/profile', + params: { id: 1 }, + headers: { 'X-Extra-Header' => '123' }, + env: { 'action_dispatch.custom' => 'custom' } + + xhr :post, '/profile', + params: { id: 1 } + MSG + end + # Performs the actual request. - def process(method, path, parameters = nil, headers_or_env = nil) + def process(method, path, params: nil, headers: nil, env: nil) if path =~ %r{://} location = URI.parse(path) https! URI::HTTPS === location if location.scheme @@ -272,9 +339,9 @@ module ActionDispatch hostname, port = host.split(':') - env = { + request_env = { :method => method, - :params => parameters, + :params => params, "SERVER_NAME" => hostname, "SERVER_PORT" => port || (https? ? "443" : "80"), @@ -287,14 +354,19 @@ module ActionDispatch "CONTENT_TYPE" => "application/x-www-form-urlencoded", "HTTP_ACCEPT" => accept } - # this modifies the passed env directly - Http::Headers.new(env).merge!(headers_or_env || {}) + # this modifies the passed request_env directly + if headers.present? + Http::Headers.new(request_env).merge!(headers) + end + if env.present? + Http::Headers.new(request_env).merge!(env) + end session = Rack::Test::Session.new(_mock_session) # NOTE: rack-test v0.5 doesn't build a default uri correctly # Make sure requested path is always a full uri - session.request(build_full_uri(path, env), env) + session.request(build_full_uri(path, request_env), request_env) @request_count += 1 @request = ActionDispatch::Request.new(session.last_request.env) diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index d0dfbfbc74..21586e2193 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -378,7 +378,9 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase end def test_render_based_on_parameters - process :render_based_on_parameters, "GET", "name" => "David" + process :render_based_on_parameters, + method: "GET", + params: { name: "David" } assert_equal "Mr. David", @response.body end diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index 001493afc0..f7ad8e5158 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -27,6 +27,16 @@ class DefaultUrlOptionsController < ActionController::Base end end +class OptionalDefaultUrlOptionsController < ActionController::Base + def show + render nothing: true + end + + def default_url_options + { format: 'atom', id: 'default-id' } + end +end + class UrlOptionsController < ActionController::Base def from_view render :inline => "<%= #{params[:route]} %>" @@ -168,7 +178,7 @@ class UrlOptionsTest < ActionController::TestCase get ':controller/:action' end - get :from_view, :route => "from_view_url" + get :from_view, params: { route: "from_view_url" } assert_equal 'http://www.override.com/from_view', @response.body assert_equal 'http://www.override.com/from_view', @controller.send(:from_view_url) @@ -202,7 +212,7 @@ class DefaultUrlOptionsTest < ActionController::TestCase get ':controller/:action' end - get :from_view, :route => "from_view_url" + get :from_view, params: { route: "from_view_url" } assert_equal 'http://www.override.com/from_view?locale=en', @response.body assert_equal 'http://www.override.com/from_view?locale=en', @controller.send(:from_view_url) @@ -219,7 +229,7 @@ class DefaultUrlOptionsTest < ActionController::TestCase get ':controller/:action' end - get :from_view, :route => "description_path(1)" + get :from_view, params: { route: "description_path(1)" } assert_equal '/en/descriptions/1', @response.body assert_equal '/en/descriptions', @controller.send(:descriptions_path) @@ -234,7 +244,18 @@ class DefaultUrlOptionsTest < ActionController::TestCase assert_equal '/en/descriptions/1.xml', @controller.send(:description_path, 1, :format => "xml") end end +end +class OptionalDefaultUrlOptionsControllerTest < ActionController::TestCase + def test_default_url_options_override_missing_positional_arguments + with_routing do |set| + set.draw do + get "/things/:id(.:format)" => 'things#show', :as => :thing + end + assert_equal '/things/1.atom', thing_path('1') + assert_equal '/things/default-id.atom', thing_path + end + end end class EmptyUrlOptionsTest < ActionController::TestCase diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index c0e6a2ebd1..4760ec1698 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -210,7 +210,7 @@ CACHED end def test_skipping_fragment_cache_digesting - get :fragment_cached_without_digest, :format => "html" + get :fragment_cached_without_digest, format: "html" assert_response :success expected_body = "<body>\n<p>ERB</p>\n</body>\n" @@ -244,7 +244,7 @@ CACHED end def test_html_formatted_fragment_caching - get :formatted_fragment_cached, :format => "html" + get :formatted_fragment_cached, format: "html" assert_response :success expected_body = "<body>\n<p>ERB</p>\n</body>\n" @@ -255,7 +255,7 @@ CACHED end def test_xml_formatted_fragment_caching - get :formatted_fragment_cached, :format => "xml" + get :formatted_fragment_cached, format: "xml" assert_response :success expected_body = "<body>\n <p>Builder</p>\n</body>\n" @@ -269,7 +269,7 @@ CACHED def test_fragment_caching_with_variant @request.variant = :phone - get :formatted_fragment_cached_with_variant, :format => "html" + get :formatted_fragment_cached_with_variant, format: "html" assert_response :success expected_body = "<body>\n<p>PHONE</p>\n</body>\n" diff --git a/actionpack/test/controller/default_url_options_with_before_action_test.rb b/actionpack/test/controller/default_url_options_with_before_action_test.rb index 656fd0431e..230f40d7ad 100644 --- a/actionpack/test/controller/default_url_options_with_before_action_test.rb +++ b/actionpack/test/controller/default_url_options_with_before_action_test.rb @@ -1,6 +1,5 @@ require 'abstract_unit' - class ControllerWithBeforeActionAndDefaultUrlOptions < ActionController::Base before_action { I18n.locale = params[:locale] } @@ -23,7 +22,7 @@ class ControllerWithBeforeActionAndDefaultUrlOptionsTest < ActionController::Tes # This test has its roots in issue #1872 test "should redirect with correct locale :de" do - get :redirect, :locale => "de" + get :redirect, params: { locale: "de" } assert_redirected_to "/controller_with_before_action_and_default_url_options/target?locale=de" end end diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index 3720a920d0..0ff0a1ef61 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -288,16 +288,16 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest def test_setting_flash_does_not_raise_in_following_requests with_test_route_set do env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new } - get '/set_flash', nil, env - get '/set_flash', nil, env + get '/set_flash', env: env + get '/set_flash', env: env end end def test_setting_flash_now_does_not_raise_in_following_requests with_test_route_set do env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new } - get '/set_flash_now', nil, env - get '/set_flash_now', nil, env + get '/set_flash_now', env: env + get '/set_flash_now', env: env end end @@ -312,9 +312,11 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest private # Overwrite get to send SessionSecret in env hash - def get(path, parameters = nil, env = {}) - env["action_dispatch.key_generator"] ||= Generator - super + def get(path, *args) + args[0] ||= {} + args[0][:env] ||= {} + args[0][:env]["action_dispatch.key_generator"] ||= Generator + super(path, *args) end def with_test_route_set diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb index 00d4612ac9..04222745d9 100644 --- a/actionpack/test/controller/force_ssl_test.rb +++ b/actionpack/test/controller/force_ssl_test.rb @@ -100,7 +100,7 @@ class ForceSSLControllerLevelTest < ActionController::TestCase end def test_banana_redirects_to_https_with_extra_params - get :banana, :token => "secret" + get :banana, params: { token: "secret" } assert_response 301 assert_equal "https://test.host/force_ssl_controller_level/banana?token=secret", redirect_to_url end @@ -273,7 +273,7 @@ class ForceSSLFormatTest < ActionController::TestCase get '/foo', :to => 'force_ssl_controller_level#banana' end - get :banana, :format => :json + get :banana, format: :json assert_response 301 assert_equal 'https://test.host/foo.json', redirect_to_url end @@ -294,7 +294,7 @@ class ForceSSLOptionalSegmentsTest < ActionController::TestCase end @request.env['PATH_INFO'] = '/en/foo' - get :banana, :locale => 'en' + get :banana, params: { locale: 'en' } assert_equal 'en', @controller.params[:locale] assert_response 301 assert_equal 'https://test.host/en/foo', redirect_to_url diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 5c0651bd73..2139cf2661 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -32,149 +32,287 @@ class SessionTest < ActiveSupport::TestCase def test_request_via_redirect_uses_given_method path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue"} - @session.expects(:process).with(:put, path, args, headers) + @session.expects(:process).with(:put, path, params: args, headers: headers) @session.stubs(:redirect?).returns(false) - @session.request_via_redirect(:put, path, args, headers) + @session.request_via_redirect(:put, path, params: args, headers: headers) + end + + def test_deprecated_request_via_redirect_uses_given_method + path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } + @session.expects(:process).with(:put, path, params: args, headers: headers) + @session.stubs(:redirect?).returns(false) + assert_deprecated { @session.request_via_redirect(:put, path, args, headers) } end def test_request_via_redirect_follows_redirects path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue"} @session.stubs(:redirect?).returns(true, true, false) @session.expects(:follow_redirect!).times(2) - @session.request_via_redirect(:get, path, args, headers) + @session.request_via_redirect(:get, path, params: args, headers: headers) end def test_request_via_redirect_returns_status path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue"} @session.stubs(:redirect?).returns(false) @session.stubs(:status).returns(200) - assert_equal 200, @session.request_via_redirect(:get, path, args, headers) + assert_equal 200, @session.request_via_redirect(:get, path, params: args, headers: headers) end - def test_get_via_redirect - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" } + def test_deprecated_get_via_redirect + path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } @session.expects(:request_via_redirect).with(:get, path, args, headers) - @session.get_via_redirect(path, args, headers) + + assert_deprecated do + @session.get_via_redirect(path, args, headers) + end end - def test_post_via_redirect - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" } + def test_deprecated_post_via_redirect + path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } @session.expects(:request_via_redirect).with(:post, path, args, headers) - @session.post_via_redirect(path, args, headers) + + assert_deprecated do + @session.post_via_redirect(path, args, headers) + end end - def test_patch_via_redirect - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" } + def test_deprecated_patch_via_redirect + path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } @session.expects(:request_via_redirect).with(:patch, path, args, headers) - @session.patch_via_redirect(path, args, headers) + + assert_deprecated do + @session.patch_via_redirect(path, args, headers) + end end - def test_put_via_redirect - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" } + def test_deprecated_put_via_redirect + path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } @session.expects(:request_via_redirect).with(:put, path, args, headers) - @session.put_via_redirect(path, args, headers) + + assert_deprecated do + @session.put_via_redirect(path, args, headers) + end end - def test_delete_via_redirect - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" } + def test_deprecated_delete_via_redirect + path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } @session.expects(:request_via_redirect).with(:delete, path, args, headers) - @session.delete_via_redirect(path, args, headers) + + assert_deprecated do + @session.delete_via_redirect(path, args, headers) + end end def test_get - path = "/index"; params = "blah"; headers = {:location => 'blah'} - @session.expects(:process).with(:get,path,params,headers) - @session.get(path,params,headers) + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:get, path, params: params, headers: headers) + @session.get(path, params: params, headers: headers) + end + + def test_get_with_env_and_headers + path = "/index"; params = "blah"; headers = { location: 'blah' }; env = { 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' } + @session.expects(:process).with(:get, path, params: params, headers: headers, env: env) + @session.get(path, params: params, headers: headers, env: env) + end + + def test_deprecated_get + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:get, path, params: params, headers: headers) + assert_deprecated { + @session.get(path, params, headers) + } end def test_post - path = "/index"; params = "blah"; headers = {:location => 'blah'} - @session.expects(:process).with(:post,path,params,headers) - @session.post(path,params,headers) + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:post, path, params: params, headers: headers) + assert_deprecated { + @session.post(path, params, headers) + } + end + + def test_deprecated_post + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:post, path, params: params, headers: headers) + @session.post(path, params: params, headers: headers) end def test_patch - path = "/index"; params = "blah"; headers = {:location => 'blah'} - @session.expects(:process).with(:patch,path,params,headers) - @session.patch(path,params,headers) + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:patch, path, params: params, headers: headers) + @session.patch(path, params: params, headers: headers) + end + + def test_deprecated_patch + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:patch, path, params: params, headers: headers) + assert_deprecated { + @session.patch(path, params, headers) + } end def test_put - path = "/index"; params = "blah"; headers = {:location => 'blah'} - @session.expects(:process).with(:put,path,params,headers) - @session.put(path,params,headers) + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:put, path, params: params, headers: headers) + @session.put(path, params: params, headers: headers) + end + + def test_deprecated_put + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:put, path, params: params, headers: headers) + assert_deprecated { + @session.put(path, params, headers) + } end def test_delete - path = "/index"; params = "blah"; headers = {:location => 'blah'} - @session.expects(:process).with(:delete,path,params,headers) - @session.delete(path,params,headers) + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:delete, path, params: params, headers: headers) + assert_deprecated { + @session.delete(path,params,headers) + } + end + + def test_deprecated_delete + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:delete, path, params: params, headers: headers) + @session.delete(path, params: params, headers: headers) end def test_head - path = "/index"; params = "blah"; headers = {:location => 'blah'} - @session.expects(:process).with(:head,path,params,headers) - @session.head(path,params,headers) + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:head, path, params: params, headers: headers) + @session.head(path, params: params, headers: headers) + end + + def deprecated_test_head + path = "/index"; params = "blah"; headers = { location: 'blah' } + @session.expects(:process).with(:head, path, params: params, headers: headers) + assert_deprecated { + @session.head(path, params, headers) + } end def test_xml_http_request_get - path = "/index"; params = "blah"; headers = {:location => 'blah'} + path = "/index"; params = "blah"; headers = { location: 'blah' } + headers_after_xhr = headers.merge( + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", + "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:get, path, params: params, headers: headers_after_xhr) + @session.xml_http_request(:get, path, params: params, headers: headers) + end + + def test_deprecated_xml_http_request_get + path = "/index"; params = "blah"; headers = { location: 'blah' } headers_after_xhr = headers.merge( "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" ) - @session.expects(:process).with(:get,path,params,headers_after_xhr) - @session.xml_http_request(:get,path,params,headers) + @session.expects(:process).with(:get, path, params: params, headers: headers_after_xhr) + assert_deprecated { + @session.xml_http_request(:get,path,params,headers) + } end def test_xml_http_request_post - path = "/index"; params = "blah"; headers = {:location => 'blah'} + path = "/index"; params = "blah"; headers = { location: 'blah' } + headers_after_xhr = headers.merge( + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", + "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:post, path, params: params, headers: headers_after_xhr) + @session.xml_http_request(:post, path, params: params, headers: headers) + end + + def test_deprecated_xml_http_request_post + path = "/index"; params = "blah"; headers = { location: 'blah' } headers_after_xhr = headers.merge( "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" ) - @session.expects(:process).with(:post,path,params,headers_after_xhr) - @session.xml_http_request(:post,path,params,headers) + @session.expects(:process).with(:post, path, params: params, headers: headers_after_xhr) + assert_deprecated { @session.xml_http_request(:post,path,params,headers) } end def test_xml_http_request_patch - path = "/index"; params = "blah"; headers = {:location => 'blah'} + path = "/index"; params = "blah"; headers = { location: 'blah' } headers_after_xhr = headers.merge( "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" ) - @session.expects(:process).with(:patch,path,params,headers_after_xhr) - @session.xml_http_request(:patch,path,params,headers) + @session.expects(:process).with(:patch, path, params: params, headers: headers_after_xhr) + @session.xml_http_request(:patch, path, params: params, headers: headers) + end + + def test_deprecated_xml_http_request_patch + path = "/index"; params = "blah"; headers = { location: 'blah' } + headers_after_xhr = headers.merge( + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", + "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:patch, path, params: params, headers: headers_after_xhr) + assert_deprecated { @session.xml_http_request(:patch,path,params,headers) } end def test_xml_http_request_put - path = "/index"; params = "blah"; headers = {:location => 'blah'} + path = "/index"; params = "blah"; headers = { location: 'blah' } + headers_after_xhr = headers.merge( + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", + "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:put, path, params: params, headers: headers_after_xhr) + @session.xml_http_request(:put, path, params: params, headers: headers) + end + + def test_deprecated_xml_http_request_put + path = "/index"; params = "blah"; headers = { location: 'blah' } headers_after_xhr = headers.merge( "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" ) - @session.expects(:process).with(:put,path,params,headers_after_xhr) - @session.xml_http_request(:put,path,params,headers) + @session.expects(:process).with(:put, path, params: params, headers: headers_after_xhr) + assert_deprecated { @session.xml_http_request(:put, path, params, headers) } end def test_xml_http_request_delete - path = "/index"; params = "blah"; headers = {:location => 'blah'} + path = "/index"; params = "blah"; headers = { location: 'blah' } headers_after_xhr = headers.merge( "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" ) - @session.expects(:process).with(:delete,path,params,headers_after_xhr) - @session.xml_http_request(:delete,path,params,headers) + @session.expects(:process).with(:delete, path, params: params, headers: headers_after_xhr) + @session.xml_http_request(:delete, path, params: params, headers: headers) + end + + def test_deprecated_xml_http_request_delete + path = "/index"; params = "blah"; headers = { location: 'blah' } + headers_after_xhr = headers.merge( + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", + "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:delete, path, params: params, headers: headers_after_xhr) + assert_deprecated { @session.xml_http_request(:delete, path, params, headers) } end def test_xml_http_request_head - path = "/index"; params = "blah"; headers = {:location => 'blah'} + path = "/index"; params = "blah"; headers = { location: 'blah' } headers_after_xhr = headers.merge( "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" ) - @session.expects(:process).with(:head,path,params,headers_after_xhr) - @session.xml_http_request(:head,path,params,headers) + @session.expects(:process).with(:head, path, params: params, headers: headers_after_xhr) + @session.xml_http_request(:head, path, params: params, headers: headers) + end + + def test_deprecated_xml_http_request_head + path = "/index"; params = "blah"; headers = { location: 'blah' } + headers_after_xhr = headers.merge( + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", + "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*" + ) + @session.expects(:process).with(:head, path, params: params, headers: headers_after_xhr) + assert_deprecated { @session.xml_http_request(:head, path, params, headers) } end def test_xml_http_request_override_accept @@ -182,8 +320,8 @@ class SessionTest < ActiveSupport::TestCase headers_after_xhr = headers.merge( "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" ) - @session.expects(:process).with(:post,path,params,headers_after_xhr) - @session.xml_http_request(:post,path,params,headers) + @session.expects(:process).with(:post, path, params: params, headers: headers_after_xhr) + @session.xml_http_request(:post, path, params: params, headers: headers) end end @@ -423,7 +561,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_get_with_parameters with_test_route_set do - get '/get_with_params', :foo => "bar" + get '/get_with_params', params: { foo: "bar" } assert_equal '/get_with_params', request.env["PATH_INFO"] assert_equal '/get_with_params', request.path_info assert_equal 'foo=bar', request.env["QUERY_STRING"] @@ -588,14 +726,22 @@ class MetalIntegrationTest < ActionDispatch::IntegrationTest end def test_pass_headers - get "/success", {}, "Referer" => "http://www.example.com/foo", "Host" => "http://nohost.com" + get "/success", headers: {"Referer" => "http://www.example.com/foo", "Host" => "http://nohost.com"} assert_equal "http://nohost.com", @request.env["HTTP_HOST"] assert_equal "http://www.example.com/foo", @request.env["HTTP_REFERER"] end + def test_pass_headers_and_env + get "/success", headers: { "X-Test-Header" => "value" }, env: { "HTTP_REFERER" => "http://test.com/", "HTTP_HOST" => "http://test.com" } + + assert_equal "http://test.com", @request.env["HTTP_HOST"] + assert_equal "http://test.com/", @request.env["HTTP_REFERER"] + assert_equal "value", @request.env["HTTP_X_TEST_HEADER"] + end + def test_pass_env - get "/success", {}, "HTTP_REFERER" => "http://test.com/", "HTTP_HOST" => "http://test.com" + get "/success", env: { "HTTP_REFERER" => "http://test.com/", "HTTP_HOST" => "http://test.com" } assert_equal "http://test.com", @request.env["HTTP_HOST"] assert_equal "http://test.com/", @request.env["HTTP_REFERER"] @@ -685,7 +831,7 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest test "process do not modify the env passed as argument" do env = { :SERVER_NAME => 'server', 'action_dispatch.custom' => 'custom' } old_env = env.dup - get '/foo', nil, env + get '/foo', env: env assert_equal old_env, env end end @@ -715,7 +861,7 @@ class EnvironmentFilterIntegrationTest < ActionDispatch::IntegrationTest end test "filters rack request form vars" do - post "/post", :username => 'cjolly', :password => 'secret' + post "/post", params: { username: 'cjolly', password: 'secret' } assert_equal 'cjolly', request.filtered_parameters['username'] assert_equal '[FILTERED]', request.filtered_parameters['password'] diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb index 864c6ee130..03a4ad7823 100644 --- a/actionpack/test/controller/log_subscriber_test.rb +++ b/actionpack/test/controller/log_subscriber_test.rb @@ -140,7 +140,7 @@ class ACLogSubscriberTest < ActionController::TestCase end def test_process_action_with_parameters - get :show, :id => '10' + get :show, params: { id: '10' } wait assert_equal 3, logs.size @@ -148,8 +148,8 @@ class ACLogSubscriberTest < ActionController::TestCase end def test_multiple_process_with_parameters - get :show, :id => '10' - get :show, :id => '20' + get :show, params: { id: '10' } + get :show, params: { id: '20' } wait @@ -160,7 +160,7 @@ class ACLogSubscriberTest < ActionController::TestCase def test_process_action_with_wrapped_parameters @request.env['CONTENT_TYPE'] = 'application/json' - post :show, :id => '10', :name => 'jose' + post :show, params: { id: '10', name: 'jose' } wait assert_equal 3, logs.size @@ -186,7 +186,9 @@ class ACLogSubscriberTest < ActionController::TestCase def test_process_action_with_filter_parameters @request.env["action_dispatch.parameter_filter"] = [:lifo, :amount] - get :show, :lifo => 'Pratik', :amount => '420', :step => '1' + get :show, params: { + lifo: 'Pratik', amount: '420', step: '1' + } wait params = logs[1] diff --git a/actionpack/test/controller/mime/accept_format_test.rb b/actionpack/test/controller/mime/accept_format_test.rb index 811c507af2..e20c08da4e 100644 --- a/actionpack/test/controller/mime/accept_format_test.rb +++ b/actionpack/test/controller/mime/accept_format_test.rb @@ -11,7 +11,7 @@ end class StarStarMimeControllerTest < ActionController::TestCase def test_javascript_with_format @request.accept = "text/javascript" - get :index, :format => 'js' + get :index, format: 'js' assert_match "function addition(a,b){ return a+b; }", @response.body end @@ -86,7 +86,7 @@ class MimeControllerLayoutsTest < ActionController::TestCase end def test_non_navigational_format_with_no_template_fallbacks_to_html_template_with_no_layout - get :index, :format => :js + get :index, format: :js assert_equal "Hello Firefox", @response.body end end diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb index 66d2fd7716..8bd32f9584 100644 --- a/actionpack/test/controller/mime/respond_to_test.rb +++ b/actionpack/test/controller/mime/respond_to_test.rb @@ -338,10 +338,10 @@ class RespondToControllerTest < ActionController::TestCase xhr :get, :json_or_yaml assert_equal 'JSON', @response.body - get :json_or_yaml, :format => 'json' + get :json_or_yaml, format: 'json' assert_equal 'JSON', @response.body - get :json_or_yaml, :format => 'yaml' + get :json_or_yaml, format: 'yaml' assert_equal 'YAML', @response.body { 'YAML' => %w(text/yaml), @@ -474,7 +474,7 @@ class RespondToControllerTest < ActionController::TestCase end def test_handle_any_any_parameter_format - get :handle_any_any, {:format=>'html'} + get :handle_any_any, format: 'html' assert_equal 'HTML', @response.body end @@ -497,7 +497,7 @@ class RespondToControllerTest < ActionController::TestCase end def test_handle_any_any_unkown_format - get :handle_any_any, { format: 'php' } + get :handle_any_any, format: 'php' assert_equal 'Whatever you ask for, I got it', @response.body end @@ -530,13 +530,13 @@ class RespondToControllerTest < ActionController::TestCase end def test_custom_constant - get :custom_constant_handling, :format => "mobile" + get :custom_constant_handling, format: "mobile" assert_equal "text/x-mobile", @response.content_type assert_equal "Mobile", @response.body end def test_custom_constant_handling_without_block - get :custom_constant_handling_without_block, :format => "mobile" + get :custom_constant_handling_without_block, format: "mobile" assert_equal "text/x-mobile", @response.content_type assert_equal "Mobile", @response.body end @@ -545,13 +545,13 @@ class RespondToControllerTest < ActionController::TestCase get :html_xml_or_rss assert_equal "HTML", @response.body - get :html_xml_or_rss, :format => "html" + get :html_xml_or_rss, format: "html" assert_equal "HTML", @response.body - get :html_xml_or_rss, :format => "xml" + get :html_xml_or_rss, format: "xml" assert_equal "XML", @response.body - get :html_xml_or_rss, :format => "rss" + get :html_xml_or_rss, format: "rss" assert_equal "RSS", @response.body end @@ -559,12 +559,12 @@ class RespondToControllerTest < ActionController::TestCase get :forced_xml assert_equal "XML", @response.body - get :forced_xml, :format => "html" + get :forced_xml, format: "html" assert_equal "XML", @response.body end def test_extension_synonyms - get :html_xml_or_rss, :format => "xhtml" + get :html_xml_or_rss, format: "xhtml" assert_equal "HTML", @response.body end @@ -581,7 +581,7 @@ class RespondToControllerTest < ActionController::TestCase get :using_defaults assert_equal "using_defaults - #{[:html]}", @response.body - get :using_defaults, :format => "xml" + get :using_defaults, format: "xml" assert_equal "using_defaults - #{[:xml]}", @response.body end @@ -589,7 +589,7 @@ class RespondToControllerTest < ActionController::TestCase get :iphone_with_html_response_type assert_equal '<html><div id="html">Hello future from Firefox!</div></html>', @response.body - get :iphone_with_html_response_type, :format => "iphone" + get :iphone_with_html_response_type, format: "iphone" assert_equal "text/html", @response.content_type assert_equal '<html><div id="iphone">Hello iPhone future from iPhone!</div></html>', @response.body end @@ -603,7 +603,7 @@ class RespondToControllerTest < ActionController::TestCase def test_invalid_format assert_raises(ActionController::UnknownFormat) do - get :using_defaults, :format => "invalidformat" + get :using_defaults, format: "invalidformat" end end diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb b/actionpack/test/controller/new_base/content_negotiation_test.rb index 5fd5946619..c8166280fc 100644 --- a/actionpack/test/controller/new_base/content_negotiation_test.rb +++ b/actionpack/test/controller/new_base/content_negotiation_test.rb @@ -15,12 +15,12 @@ module ContentNegotiation class TestContentNegotiation < Rack::TestCase test "A */* Accept header will return HTML" do - get "/content_negotiation/basic/hello", {}, "HTTP_ACCEPT" => "*/*" + get "/content_negotiation/basic/hello", headers: { "HTTP_ACCEPT" => "*/*" } assert_body "Hello world */*!" end test "Not all mimes are converted to symbol" do - get "/content_negotiation/basic/all", {}, "HTTP_ACCEPT" => "text/plain, mime/another" + get "/content_negotiation/basic/all", headers: { "HTTP_ACCEPT" => "text/plain, mime/another" } assert_body '[:text, "mime/another"]' end end diff --git a/actionpack/test/controller/new_base/content_type_test.rb b/actionpack/test/controller/new_base/content_type_test.rb index 9b57641e75..88453988dd 100644 --- a/actionpack/test/controller/new_base/content_type_test.rb +++ b/actionpack/test/controller/new_base/content_type_test.rb @@ -76,7 +76,7 @@ module ContentType end test "sets Content-Type as application/xml when rendering *.xml.erb" do - get "/content_type/implied/i_am_xml_erb", "format" => "xml" + get "/content_type/implied/i_am_xml_erb", params: { "format" => "xml" } assert_header "Content-Type", "application/xml; charset=utf-8" end @@ -88,7 +88,7 @@ module ContentType end test "sets Content-Type as application/xml when rendering *.xml.builder" do - get "/content_type/implied/i_am_xml_builder", "format" => "xml" + get "/content_type/implied/i_am_xml_builder", params: { "format" => "xml" } assert_header "Content-Type", "application/xml; charset=utf-8" end diff --git a/actionpack/test/controller/new_base/render_action_test.rb b/actionpack/test/controller/new_base/render_action_test.rb index 475bf9d3c9..3bf1dd0ede 100644 --- a/actionpack/test/controller/new_base/render_action_test.rb +++ b/actionpack/test/controller/new_base/render_action_test.rb @@ -88,7 +88,7 @@ module RenderAction test "rendering with layout => true" do assert_raise(ArgumentError) do - get "/render_action/basic/hello_world_with_layout", {}, "action_dispatch.show_exceptions" => false + get "/render_action/basic/hello_world_with_layout", headers: { "action_dispatch.show_exceptions" => false } end end @@ -108,7 +108,7 @@ module RenderAction test "rendering with layout => 'greetings'" do assert_raise(ActionView::MissingTemplate) do - get "/render_action/basic/hello_world_with_custom_layout", {}, "action_dispatch.show_exceptions" => false + get "/render_action/basic/hello_world_with_custom_layout", headers: { "action_dispatch.show_exceptions" => false } end end end diff --git a/actionpack/test/controller/new_base/render_layout_test.rb b/actionpack/test/controller/new_base/render_layout_test.rb index 4ac40ca405..7ab3777026 100644 --- a/actionpack/test/controller/new_base/render_layout_test.rb +++ b/actionpack/test/controller/new_base/render_layout_test.rb @@ -86,7 +86,7 @@ module ControllerLayouts XML_INSTRUCT = %Q(<?xml version="1.0" encoding="UTF-8"?>\n) test "if XML is selected, an HTML template is not also selected" do - get :index, :format => "xml" + get :index, params: { format: "xml" } assert_response XML_INSTRUCT end @@ -96,7 +96,7 @@ module ControllerLayouts end test "a layout for JS is ignored even if explicitly provided for HTML" do - get :explicit, { :format => "js" } + get :explicit, params: { format: "js" } assert_response "alert('foo');" end end @@ -120,7 +120,7 @@ module ControllerLayouts testing ControllerLayouts::FalseLayoutMethodController test "access false layout returned by a method/proc" do - get :index, :format => "js" + get :index, params: { format: "js" } assert_response "alert('foo');" end end diff --git a/actionpack/test/controller/new_base/render_streaming_test.rb b/actionpack/test/controller/new_base/render_streaming_test.rb index 4c9126ca8c..9ea056194a 100644 --- a/actionpack/test/controller/new_base/render_streaming_test.rb +++ b/actionpack/test/controller/new_base/render_streaming_test.rb @@ -97,7 +97,7 @@ module RenderStreaming end test "do not stream on HTTP/1.0" do - get "/render_streaming/basic/hello_world", nil, "HTTP_VERSION" => "HTTP/1.0" + get "/render_streaming/basic/hello_world", headers: { "HTTP_VERSION" => "HTTP/1.0" } assert_body "Hello world, I'm here!" assert_status 200 assert_equal "22", headers["Content-Length"] diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb index 42a86b1d0d..19fef718e7 100644 --- a/actionpack/test/controller/new_base/render_template_test.rb +++ b/actionpack/test/controller/new_base/render_template_test.rb @@ -111,7 +111,7 @@ module RenderTemplate end test "rendering a builder template" do - get :builder_template, "format" => "xml" + get :builder_template, params: { "format" => "xml" } assert_response "<html>\n <p>Hello</p>\n</html>\n" end @@ -126,7 +126,7 @@ module RenderTemplate assert_body "Hello <strong>this is also raw</strong> in an html template" assert_status 200 - get :with_implicit_raw, format: 'text' + get :with_implicit_raw, params: { format: 'text' } assert_body "Hello <strong>this is also raw</strong> in a text template" assert_status 200 diff --git a/actionpack/test/controller/new_base/render_test.rb b/actionpack/test/controller/new_base/render_test.rb index 5635e16234..11a19ab783 100644 --- a/actionpack/test/controller/new_base/render_test.rb +++ b/actionpack/test/controller/new_base/render_test.rb @@ -74,7 +74,7 @@ module Render end assert_raises(AbstractController::DoubleRenderError) do - get "/render/double_render", {}, "action_dispatch.show_exceptions" => false + get "/render/double_render", headers: { "action_dispatch.show_exceptions" => false } end end end @@ -84,13 +84,13 @@ module Render # Only public methods on actual controllers are callable actions test "raises an exception when a method of Object is called" do assert_raises(AbstractController::ActionNotFound) do - get "/render/blank_render/clone", {}, "action_dispatch.show_exceptions" => false + get "/render/blank_render/clone", headers: { "action_dispatch.show_exceptions" => false } end end test "raises an exception when a private method is called" do assert_raises(AbstractController::ActionNotFound) do - get "/render/blank_render/secretz", {}, "action_dispatch.show_exceptions" => false + get "/render/blank_render/secretz", headers: { "action_dispatch.show_exceptions" => false } end end end diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index 645ecae220..8bf016d060 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -40,7 +40,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_filtered_parameters with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu' } + post :parse, params: { 'username' => 'sikachu' } assert_equal @request.filtered_parameters, { 'controller' => 'params_wrapper_test/users', 'action' => 'parse', 'username' => 'sikachu', 'user' => { 'username' => 'sikachu' } } end end @@ -48,7 +48,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_derived_name_from_controller with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu' } + post :parse, params: { 'username' => 'sikachu' } assert_parameters({ 'username' => 'sikachu', 'user' => { 'username' => 'sikachu' }}) end end @@ -58,7 +58,7 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.wrap_parameters :person @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu' } + post :parse, params: { 'username' => 'sikachu' } assert_parameters({ 'username' => 'sikachu', 'person' => { 'username' => 'sikachu' }}) end end @@ -68,7 +68,7 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.wrap_parameters Person @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu' } + post :parse, params: { 'username' => 'sikachu' } assert_parameters({ 'username' => 'sikachu', 'person' => { 'username' => 'sikachu' }}) end end @@ -78,7 +78,7 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.wrap_parameters :include => :username @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) end end @@ -88,7 +88,7 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.wrap_parameters :exclude => :title @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) end end @@ -98,7 +98,7 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.wrap_parameters :person, :include => :username @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }}) end end @@ -106,7 +106,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_not_enabled_format with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/xml' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer' }) end end @@ -115,7 +115,7 @@ class ParamsWrapperTest < ActionController::TestCase with_default_wrapper_options do UsersController.wrap_parameters false @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer' }) end end @@ -125,7 +125,7 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.wrap_parameters :format => :xml @request.env['CONTENT_TYPE'] = 'application/xml' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }}) end end @@ -133,7 +133,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_not_wrap_reserved_parameters with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'authenticity_token' => 'pwned', '_method' => 'put', 'utf8' => '☃', 'username' => 'sikachu' } + post :parse, params: { 'authenticity_token' => 'pwned', '_method' => 'put', 'utf8' => '☃', 'username' => 'sikachu' } assert_parameters({ 'authenticity_token' => 'pwned', '_method' => 'put', 'utf8' => '☃', 'username' => 'sikachu', 'user' => { 'username' => 'sikachu' }}) end end @@ -141,7 +141,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_no_double_wrap_if_key_exists with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'user' => { 'username' => 'sikachu' }} + post :parse, params: { 'user' => { 'username' => 'sikachu' }} assert_parameters({ 'user' => { 'username' => 'sikachu' }}) end end @@ -149,7 +149,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_nested_params with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'person' => { 'username' => 'sikachu' }} + post :parse, params: { 'person' => { 'username' => 'sikachu' }} assert_parameters({ 'person' => { 'username' => 'sikachu' }, 'user' => {'person' => { 'username' => 'sikachu' }}}) end end @@ -160,7 +160,7 @@ class ParamsWrapperTest < ActionController::TestCase with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) end end @@ -173,7 +173,7 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.wrap_parameters Person @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }}) end end @@ -184,7 +184,7 @@ class ParamsWrapperTest < ActionController::TestCase with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }}) end end @@ -192,7 +192,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_preserves_query_string_params with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - get :parse, { 'user' => { 'username' => 'nixon' } } + get :parse, params: { 'user' => { 'username' => 'nixon' } } assert_parameters( {'user' => { 'username' => 'nixon' } } ) @@ -202,7 +202,7 @@ class ParamsWrapperTest < ActionController::TestCase def test_empty_parameter_set with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, {} + post :parse, params: {} assert_parameters( {'user' => { } } ) @@ -249,7 +249,7 @@ class NamespacedParamsWrapperTest < ActionController::TestCase def test_derived_name_from_controller with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu' } + post :parse, params: { 'username' => 'sikachu' } assert_parameters({'username' => 'sikachu', 'user' => { 'username' => 'sikachu' }}) end end @@ -259,7 +259,7 @@ class NamespacedParamsWrapperTest < ActionController::TestCase begin with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) end ensure @@ -272,7 +272,7 @@ class NamespacedParamsWrapperTest < ActionController::TestCase begin with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'title' => 'Developer' } + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'title' => 'Developer' }}) end ensure @@ -299,7 +299,7 @@ class AnonymousControllerParamsWrapperTest < ActionController::TestCase def test_does_not_implicitly_wrap_params with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu' } + post :parse, params: { 'username' => 'sikachu' } assert_parameters({ 'username' => 'sikachu' }) end end @@ -308,7 +308,7 @@ class AnonymousControllerParamsWrapperTest < ActionController::TestCase with_default_wrapper_options do @controller.class.wrap_parameters(:name => "guest") @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu' } + post :parse, params: { 'username' => 'sikachu' } assert_parameters({ 'username' => 'sikachu', 'guest' => { 'username' => 'sikachu' }}) end end @@ -344,7 +344,7 @@ class IrregularInflectionParamsWrapperTest < ActionController::TestCase with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'test_attr' => 'test_value' } + post :parse, params: { 'username' => 'sikachu', 'test_attr' => 'test_value' } assert_parameters({ 'username' => 'sikachu', 'test_attr' => 'test_value', 'paramswrappernews_item' => { 'test_attr' => 'test_value' }}) end end diff --git a/actionpack/test/controller/permitted_params_test.rb b/actionpack/test/controller/permitted_params_test.rb index f46249d712..7136fafae5 100644 --- a/actionpack/test/controller/permitted_params_test.rb +++ b/actionpack/test/controller/permitted_params_test.rb @@ -14,12 +14,12 @@ class ActionControllerPermittedParamsTest < ActionController::TestCase tests PeopleController test "parameters are forbidden" do - post :create, { person: { name: "Mjallo!" } } + post :create, params: { person: { name: "Mjallo!" } } assert_equal "forbidden", response.body end test "parameters can be permitted and are then not forbidden" do - post :create_with_permit, { person: { name: "Mjallo!" } } + post :create_with_permit, params: { person: { name: "Mjallo!" } } assert_equal "permitted", response.body end end diff --git a/actionpack/test/controller/render_js_test.rb b/actionpack/test/controller/render_js_test.rb index d550422a2f..d482df195f 100644 --- a/actionpack/test/controller/render_js_test.rb +++ b/actionpack/test/controller/render_js_test.rb @@ -28,7 +28,7 @@ class RenderJSTest < ActionController::TestCase end def test_should_render_js_partial - xhr :get, :show_partial, :format => 'js' + xhr :get, :show_partial, format: 'js' assert_equal 'partial js', @response.body end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 108a35f59f..1c3f436cfa 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -462,21 +462,21 @@ class HeadRenderTest < ActionController::TestCase end def test_head_with_symbolic_status - get :head_with_symbolic_status, :status => "ok" + get :head_with_symbolic_status, params: { status: "ok" } assert_equal 200, @response.status assert_response :ok - get :head_with_symbolic_status, :status => "not_found" + get :head_with_symbolic_status, params: { status: "not_found" } assert_equal 404, @response.status assert_response :not_found - get :head_with_symbolic_status, :status => "no_content" + get :head_with_symbolic_status, params: { status: "no_content" } assert_equal 204, @response.status assert !@response.headers.include?('Content-Length') assert_response :no_content Rack::Utils::SYMBOL_TO_STATUS_CODE.each do |status, code| - get :head_with_symbolic_status, :status => status.to_s + get :head_with_symbolic_status, params: { status: status.to_s } assert_equal code, @response.response_code assert_response status end @@ -484,7 +484,7 @@ class HeadRenderTest < ActionController::TestCase def test_head_with_integer_status Rack::Utils::HTTP_STATUS_CODES.each do |code, message| - get :head_with_integer_status, :status => code.to_s + get :head_with_integer_status, params: { status: code.to_s } assert_equal message, @response.message end end @@ -498,7 +498,7 @@ class HeadRenderTest < ActionController::TestCase end def test_head_with_string_status - get :head_with_string_status, :status => "404 Eat Dirt" + get :head_with_string_status, params: { status: "404 Eat Dirt" } assert_equal 404, @response.response_code assert_equal "Not Found", @response.message assert_response :not_found diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb index 4f280c4bec..7a91577b17 100644 --- a/actionpack/test/controller/render_xml_test.rb +++ b/actionpack/test/controller/render_xml_test.rb @@ -81,7 +81,7 @@ class RenderXmlTest < ActionController::TestCase end def test_should_render_formatted_xml_erb_template - get :formatted_xml_erb, :format => :xml + get :formatted_xml_erb, format: :xml assert_equal '<test>passed formatted xml erb</test>', @response.body end @@ -91,7 +91,7 @@ class RenderXmlTest < ActionController::TestCase end def test_should_use_implicit_content_type - get :implicit_content_type, :format => 'atom' + get :implicit_content_type, format: 'atom' assert_equal Mime::ATOM, @response.content_type end end diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index ea2d35c3f8..8a0eed5a87 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -266,19 +266,19 @@ module RequestForgeryProtectionTests end def test_should_allow_post_with_token - assert_not_blocked { post :index, :custom_authenticity_token => @token } + assert_not_blocked { post :index, params: { custom_authenticity_token: @token } } end def test_should_allow_patch_with_token - assert_not_blocked { patch :index, :custom_authenticity_token => @token } + assert_not_blocked { patch :index, params: { custom_authenticity_token: @token } } end def test_should_allow_put_with_token - assert_not_blocked { put :index, :custom_authenticity_token => @token } + assert_not_blocked { put :index, params: { custom_authenticity_token: @token } } end def test_should_allow_delete_with_token - assert_not_blocked { delete :index, :custom_authenticity_token => @token } + assert_not_blocked { delete :index, params: { custom_authenticity_token: @token } } end def test_should_allow_post_with_token_in_header @@ -341,7 +341,7 @@ module RequestForgeryProtectionTests end assert_cross_origin_not_blocked { xhr :get, :same_origin_js } - assert_cross_origin_not_blocked { xhr :get, :same_origin_js, format: 'js' } + assert_cross_origin_not_blocked { xhr :get, :same_origin_js, format: 'js'} assert_cross_origin_not_blocked do @request.accept = 'text/javascript' xhr :get, :negotiate_same_origin @@ -350,11 +350,11 @@ module RequestForgeryProtectionTests # Allow non-GET requests since GET is all a remote <script> tag can muster. def test_should_allow_non_get_js_without_xhr_header - assert_cross_origin_not_blocked { post :same_origin_js, custom_authenticity_token: @token } - assert_cross_origin_not_blocked { post :same_origin_js, format: 'js', custom_authenticity_token: @token } + assert_cross_origin_not_blocked { post :same_origin_js, params: { custom_authenticity_token: @token } } + assert_cross_origin_not_blocked { post :same_origin_js, params: { format: 'js', custom_authenticity_token: @token } } assert_cross_origin_not_blocked do @request.accept = 'text/javascript' - post :negotiate_same_origin, custom_authenticity_token: @token + post :negotiate_same_origin, params: { custom_authenticity_token: @token} end end @@ -543,7 +543,7 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase @controller.stubs(:valid_authenticity_token?).returns(:true) begin - post :index, :custom_token_name => 'foobar' + post :index, params: { custom_token_name: 'foobar' } assert_equal 0, @logger.logged(:warn).size ensure ActionController::Base.logger = @old_logger @@ -554,7 +554,7 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase ActionController::Base.logger = @logger begin - post :index, :custom_token_name => 'bazqux' + post :index, params: { custom_token_name: 'bazqux' } assert_equal 1, @logger.logged(:warn).size ensure ActionController::Base.logger = @old_logger diff --git a/actionpack/test/controller/required_params_test.rb b/actionpack/test/controller/required_params_test.rb index 6803dbbb62..a901e56332 100644 --- a/actionpack/test/controller/required_params_test.rb +++ b/actionpack/test/controller/required_params_test.rb @@ -12,21 +12,21 @@ class ActionControllerRequiredParamsTest < ActionController::TestCase test "missing required parameters will raise exception" do assert_raise ActionController::ParameterMissing do - post :create, { magazine: { name: "Mjallo!" } } + post :create, params: { magazine: { name: "Mjallo!" } } end assert_raise ActionController::ParameterMissing do - post :create, { book: { title: "Mjallo!" } } + post :create, params: { book: { title: "Mjallo!" } } end end test "required parameters that are present will not raise" do - post :create, { book: { name: "Mjallo!" } } + post :create, params: { book: { name: "Mjallo!" } } assert_response :ok end test "required parameters with false value will not raise" do - post :create, { book: { name: false } } + post :create, params: { book: { name: false } } assert_response :ok end end diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 0e15883f43..05806177e3 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -1187,7 +1187,7 @@ class ResourcesTest < ActionController::TestCase @controller.singleton_class.send(:include, @routes.url_helpers) @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new - get :index, options[:options] + get :index, params: options[:options] options[:options].delete :action path = "#{options[:as] || controller_name}" @@ -1257,7 +1257,7 @@ class ResourcesTest < ActionController::TestCase @controller.singleton_class.send(:include, @routes.url_helpers) @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new - get :show, options[:options] + get :show, params: options[:options] options[:options].delete :action full_path = "/#{options[:path_prefix]}#{options[:as] || singleton_name}" diff --git a/actionpack/test/controller/show_exceptions_test.rb b/actionpack/test/controller/show_exceptions_test.rb index f7eba1ef43..fba5ebba15 100644 --- a/actionpack/test/controller/show_exceptions_test.rb +++ b/actionpack/test/controller/show_exceptions_test.rb @@ -58,13 +58,13 @@ module ShowExceptions class ShowExceptionsOverriddenTest < ActionDispatch::IntegrationTest test 'show error page' do @app = ShowExceptionsOverriddenController.action(:boom) - get '/', {'detailed' => '0'} + get '/', params: { 'detailed' => '0' } assert_equal "500 error fixture\n", body end test 'show diagnostics message' do @app = ShowExceptionsOverriddenController.action(:boom) - get '/', {'detailed' => '1'} + get '/', params: { 'detailed' => '1' } assert_match(/boom/, body) end end @@ -72,7 +72,7 @@ module ShowExceptions class ShowExceptionsFormatsTest < ActionDispatch::IntegrationTest def test_render_json_exception @app = ShowExceptionsOverriddenController.action(:boom) - get "/", {}, 'HTTP_ACCEPT' => 'application/json' + get "/", headers: { 'HTTP_ACCEPT' => 'application/json' } assert_response :internal_server_error assert_equal 'application/json', response.content_type.to_s assert_equal({ :status => '500', :error => 'Internal Server Error' }.to_json, response.body) @@ -80,7 +80,7 @@ module ShowExceptions def test_render_xml_exception @app = ShowExceptionsOverriddenController.action(:boom) - get "/", {}, 'HTTP_ACCEPT' => 'application/xml' + get "/", headers: { 'HTTP_ACCEPT' => 'application/xml' } assert_response :internal_server_error assert_equal 'application/xml', response.content_type.to_s assert_equal({ :status => '500', :error => 'Internal Server Error' }.to_xml, response.body) @@ -88,7 +88,7 @@ module ShowExceptions def test_render_fallback_exception @app = ShowExceptionsOverriddenController.action(:boom) - get "/", {}, 'HTTP_ACCEPT' => 'text/csv' + get "/", headers: { 'HTTP_ACCEPT' => 'text/csv' } assert_response :internal_server_error assert_equal 'text/html', response.content_type.to_s end @@ -101,7 +101,7 @@ module ShowExceptions @app.instance_variable_set(:@exceptions_app, nil) $stderr = StringIO.new - get '/', {}, 'HTTP_ACCEPT' => 'text/json' + get '/', headers: { 'HTTP_ACCEPT' => 'text/json' } assert_response :internal_server_error assert_equal 'text/plain', response.content_type.to_s ensure diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index 2e1f21c645..901db63e39 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -6,57 +6,57 @@ require 'rails/engine' class TestCaseTest < ActionController::TestCase class TestController < ActionController::Base def no_op - render :text => 'dummy' + render text: 'dummy' end def set_flash flash["test"] = ">#{flash["test"]}<" - render :text => 'ignore me' + render text: 'ignore me' end def set_flash_now flash.now["test_now"] = ">#{flash["test_now"]}<" - render :text => 'ignore me' + render text: 'ignore me' end def set_session session['string'] = 'A wonder' session[:symbol] = 'it works' - render :text => 'Success' + render text: 'Success' end def reset_the_session reset_session - render :text => 'ignore me' + render text: 'ignore me' end def render_raw_post raise ActiveSupport::TestCase::Assertion, "#raw_post is blank" if request.raw_post.blank? - render :text => request.raw_post + render text: request.raw_post end def render_body - render :text => request.body.read + render text: request.body.read end def test_params - render :text => params.inspect + render text: params.inspect end def test_uri - render :text => request.fullpath + render text: request.fullpath end def test_format - render :text => request.format + render text: request.format end def test_query_string - render :text => request.query_string + render text: request.query_string end def test_protocol - render :text => request.protocol + render text: request.protocol end def test_headers @@ -64,7 +64,7 @@ class TestCaseTest < ActionController::TestCase end def test_html_output - render :text => <<HTML + render text: <<HTML <html> <body> <a href="/"><img src="/images/button.png" /></a> @@ -86,7 +86,7 @@ HTML def test_xml_output response.content_type = "application/xml" - render :text => <<XML + render text: <<XML <?xml version="1.0" encoding="UTF-8"?> <root> <area>area is an empty tag in HTML, raising an error if not in xml mode</area> @@ -95,15 +95,15 @@ XML end def test_only_one_param - render :text => (params[:left] && params[:right]) ? "EEP, Both here!" : "OK" + render text: (params[:left] && params[:right]) ? "EEP, Both here!" : "OK" end def test_remote_addr - render :text => (request.remote_addr || "not specified") + render text: (request.remote_addr || "not specified") end def test_file_upload - render :text => params[:file].size + render text: params[:file].size end def test_send_file @@ -111,26 +111,26 @@ XML end def redirect_to_same_controller - redirect_to :controller => 'test', :action => 'test_uri', :id => 5 + redirect_to controller: 'test', action: 'test_uri', id: 5 end def redirect_to_different_controller - redirect_to :controller => 'fail', :id => 5 + redirect_to controller: 'fail', id: 5 end def create - head :created, :location => 'created resource' + head :created, location: 'created resource' end def delete_cookie cookies.delete("foo") - render :nothing => true + render nothing: true end def test_assigns @foo = "foo" - @foo_hash = {:foo => :bar} - render :nothing => true + @foo_hash = { foo: :bar } + render nothing: true end def test_without_body @@ -144,7 +144,7 @@ XML private def generate_url(opts) - url_for(opts.merge(:action => "test_uri")) + url_for(opts.merge(action: "test_uri")) end end @@ -164,7 +164,7 @@ XML class ViewAssignsController < ActionController::Base def test_assigns @foo = "foo" - render :nothing => true + render nothing: true end def view_assigns @@ -209,32 +209,50 @@ XML end def test_raw_post_handling - params = Hash[:page, {:name => 'page name'}, 'some key', 123] - post :render_raw_post, params.dup + params = Hash[:page, { name: 'page name' }, 'some key', 123] + post :render_raw_post, params: params.dup assert_equal params.to_query, @response.body end def test_body_stream - params = Hash[:page, { :name => 'page name' }, 'some key', 123] + params = Hash[:page, { name: 'page name' }, 'some key', 123] - post :render_body, params.dup + post :render_body, params: params.dup + + assert_equal params.to_query, @response.body + end + + def test_deprecated_body_stream + params = Hash[:page, { name: 'page name' }, 'some key', 123] + + assert_deprecated { post :render_body, params.dup } assert_equal params.to_query, @response.body end def test_document_body_and_params_with_post - post :test_params, :id => 1 - assert_equal("{\"id\"=>\"1\", \"controller\"=>\"test_case_test/test\", \"action\"=>\"test_params\"}", @response.body) + post :test_params, params: { id: 1 } + assert_equal(%({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}), @response.body) end def test_document_body_with_post - post :render_body, "document body" + post :render_body, body: "document body" + assert_equal "document body", @response.body + end + + def test_deprecated_document_body_with_post + assert_deprecated { post :render_body, "document body" } assert_equal "document body", @response.body end def test_document_body_with_put - put :render_body, "document body" + put :render_body, body: "document body" + assert_equal "document body", @response.body + end + + def test_deprecated_document_body_with_put + assert_deprecated { put :render_body, "document body" } assert_equal "document body", @response.body end @@ -243,22 +261,32 @@ XML assert_equal 200, @response.status end - def test_head_params_as_string - assert_raise(NoMethodError) { head :test_params, "document body", :id => 10 } - end - def test_process_without_flash process :set_flash assert_equal '><', flash['test'] end + def test_deprecated_process_with_flash + assert_deprecated { process :set_flash, "GET", nil, nil, { "test" => "value" } } + assert_equal '>value<', flash['test'] + end + def test_process_with_flash - process :set_flash, "GET", nil, nil, { "test" => "value" } + process :set_flash, + method: "GET", + flash: { "test" => "value" } assert_equal '>value<', flash['test'] end + def test_deprecated_process_with_flash_now + assert_deprecated { process :set_flash_now, "GET", nil, nil, { "test_now" => "value_now" } } + assert_equal '>value_now<', flash['test_now'] + end + def test_process_with_flash_now - process :set_flash_now, "GET", nil, nil, { "test_now" => "value_now" } + process :set_flash_now, + method: "GET", + flash: { "test_now" => "value_now" } assert_equal '>value_now<', flash['test_now'] end @@ -271,22 +299,48 @@ XML end def test_process_with_session_arg - process :no_op, "GET", nil, { 'string' => 'value1', :symbol => 'value2' } + assert_deprecated { process :no_op, "GET", nil, { 'string' => 'value1', symbol: 'value2' } } assert_equal 'value1', session['string'] assert_equal 'value1', session[:string] assert_equal 'value2', session['symbol'] assert_equal 'value2', session[:symbol] end + def test_process_with_session_kwarg + process :no_op, method: "GET", session: { 'string' => 'value1', symbol: 'value2' } + assert_equal 'value1', session['string'] + assert_equal 'value1', session[:string] + assert_equal 'value2', session['symbol'] + assert_equal 'value2', session[:symbol] + end + + def test_deprecated_process_merges_session_arg + session[:foo] = 'bar' + assert_deprecated { + get :no_op, nil, { bar: 'baz' } + } + assert_equal 'bar', session[:foo] + assert_equal 'baz', session[:bar] + end + def test_process_merges_session_arg session[:foo] = 'bar' - get :no_op, nil, { :bar => 'baz' } + get :no_op, session: { bar: 'baz' } assert_equal 'bar', session[:foo] assert_equal 'baz', session[:bar] end + def test_deprecated_merged_session_arg_is_retained_across_requests + assert_deprecated { + get :no_op, nil, { foo: 'bar' } + } + assert_equal 'bar', session[:foo] + get :no_op + assert_equal 'bar', session[:foo] + end + def test_merged_session_arg_is_retained_across_requests - get :no_op, nil, { :foo => 'bar' } + get :no_op, session: { foo: 'bar' } assert_equal 'bar', session[:foo] get :no_op assert_equal 'bar', session[:foo] @@ -294,7 +348,7 @@ XML def test_process_overwrites_existing_session_arg session[:foo] = 'bar' - get :no_op, nil, { :foo => 'baz' } + get :no_op, session: { foo: 'baz' } assert_equal 'baz', session[:foo] end @@ -321,19 +375,40 @@ XML assert_equal "/test_case_test/test/test_uri", @response.body end + def test_process_with_symbol_method + process :test_uri, method: :get + assert_equal "/test_case_test/test/test_uri", @response.body + end + + def test_deprecated_process_with_request_uri_with_params + assert_deprecated { process :test_uri, "GET", id: 7 } + assert_equal "/test_case_test/test/test_uri/7", @response.body + end + def test_process_with_request_uri_with_params - process :test_uri, "GET", :id => 7 + process :test_uri, + method: "GET", + params: { id: 7 } + assert_equal "/test_case_test/test/test_uri/7", @response.body end + def test_deprecated_process_with_request_uri_with_params_with_explicit_uri + @request.env['PATH_INFO'] = "/explicit/uri" + assert_deprecated { process :test_uri, "GET", id: 7 } + assert_equal "/explicit/uri", @response.body + end + def test_process_with_request_uri_with_params_with_explicit_uri @request.env['PATH_INFO'] = "/explicit/uri" - process :test_uri, "GET", :id => 7 + process :test_uri, method: "GET", params: { id: 7 } assert_equal "/explicit/uri", @response.body end def test_process_with_query_string - process :test_query_string, "GET", :q => 'test' + process :test_query_string, + method: "GET", + params: { q: 'test' } assert_equal "q=test", @response.body end @@ -345,9 +420,9 @@ XML end def test_multiple_calls - process :test_only_one_param, "GET", :left => true + process :test_only_one_param, method: "GET", params: { left: true } assert_equal "OK", @response.body - process :test_only_one_param, "GET", :right => true + process :test_only_one_param, method: "GET", params: { right: true } assert_equal "OK", @response.body end @@ -362,7 +437,7 @@ XML assert_equal "foo", assigns["foo"] # but the assigned variable should not have its own keys stringified - expected_hash = { :foo => :bar } + expected_hash = { foo: :bar } assert_equal expected_hash, assigns(:foo_hash) end @@ -390,21 +465,21 @@ XML end def test_assert_generates - assert_generates 'controller/action/5', :controller => 'controller', :action => 'action', :id => '5' - assert_generates 'controller/action/7', {:id => "7"}, {:controller => "controller", :action => "action"} - assert_generates 'controller/action/5', {:controller => "controller", :action => "action", :id => "5", :name => "bob"}, {}, {:name => "bob"} - assert_generates 'controller/action/7', {:id => "7", :name => "bob"}, {:controller => "controller", :action => "action"}, {:name => "bob"} - assert_generates 'controller/action/7', {:id => "7"}, {:controller => "controller", :action => "action", :name => "bob"}, {} + assert_generates 'controller/action/5', controller: 'controller', action: 'action', id: '5' + assert_generates 'controller/action/7', { id: "7" }, { controller: "controller", action: "action" } + assert_generates 'controller/action/5', { controller: "controller", action: "action", id: "5", name: "bob" }, {}, { name: "bob" } + assert_generates 'controller/action/7', { id: "7", name: "bob" }, { controller: "controller", action: "action" }, { name: "bob" } + assert_generates 'controller/action/7', { id: "7" }, { controller: "controller", action: "action", name: "bob" }, {} end def test_assert_routing - assert_routing 'content', :controller => 'content', :action => 'index' + assert_routing 'content', controller: 'content', action: 'index' end def test_assert_routing_with_method with_routing do |set| set.draw { resources(:content) } - assert_routing({ :method => 'post', :path => 'content' }, { :controller => 'content', :action => 'create' }) + assert_routing({ method: 'post', path: 'content' }, { controller: 'content', action: 'create' }) end end @@ -416,29 +491,75 @@ XML end end - assert_routing 'admin/user', :controller => 'admin/user', :action => 'index' + assert_routing 'admin/user', controller: 'admin/user', action: 'index' end end def test_assert_routing_with_glob with_routing do |set| set.draw { get('*path' => "pages#show") } - assert_routing('/company/about', { :controller => 'pages', :action => 'show', :path => 'company/about' }) + assert_routing('/company/about', { controller: 'pages', action: 'show', path: 'company/about' }) end end + def test_deprecated_params_passing + assert_deprecated { + get :test_params, page: { name: "Page name", month: '4', year: '2004', day: '6' } + } + parsed_params = eval(@response.body) + assert_equal( + { + 'controller' => 'test_case_test/test', 'action' => 'test_params', + 'page' => { 'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6' } + }, + parsed_params + ) + end + def test_params_passing - get :test_params, :page => {:name => "Page name", :month => '4', :year => '2004', :day => '6'} + get :test_params, params: { + page: { + name: "Page name", + month: '4', + year: '2004', + day: '6' + } + } + parsed_params = eval(@response.body) + assert_equal( + { + 'controller' => 'test_case_test/test', 'action' => 'test_params', + 'page' => { 'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6' } + }, + parsed_params + ) + end + + def test_kwarg_params_passing_with_session_and_flash + get :test_params, params: { + page: { + name: "Page name", + month: '4', + year: '2004', + day: '6' + } + }, session: { 'foo' => 'bar' }, flash: { notice: 'created' } + parsed_params = eval(@response.body) assert_equal( {'controller' => 'test_case_test/test', 'action' => 'test_params', 'page' => {'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6'}}, parsed_params ) + + assert_equal 'bar', session[:foo] + assert_equal 'created', flash[:notice] end def test_params_passing_with_fixnums - get :test_params, :page => {:name => "Page name", :month => 4, :year => 2004, :day => 6} + get :test_params, params: { + page: { name: "Page name", month: 4, year: 2004, day: 6 } + } parsed_params = eval(@response.body) assert_equal( {'controller' => 'test_case_test/test', 'action' => 'test_params', @@ -448,7 +569,7 @@ XML end def test_params_passing_with_fixnums_when_not_html_request - get :test_params, :format => 'json', :count => 999 + get :test_params, params: { format: 'json', count: 999 } parsed_params = eval(@response.body) assert_equal( {'controller' => 'test_case_test/test', 'action' => 'test_params', @@ -458,7 +579,17 @@ XML end def test_params_passing_path_parameter_is_string_when_not_html_request - get :test_params, :format => 'json', :id => 1 + get :test_params, params: { format: 'json', id: 1 } + parsed_params = eval(@response.body) + assert_equal( + {'controller' => 'test_case_test/test', 'action' => 'test_params', + 'format' => 'json', 'id' => '1' }, + parsed_params + ) + end + + def test_deprecated_params_passing_path_parameter_is_string_when_not_html_request + assert_deprecated { get :test_params, format: 'json', id: 1 } parsed_params = eval(@response.body) assert_equal( {'controller' => 'test_case_test/test', 'action' => 'test_params', @@ -469,7 +600,9 @@ XML def test_params_passing_with_frozen_values assert_nothing_raised do - get :test_params, :frozen => 'icy'.freeze, :frozens => ['icy'.freeze].freeze, :deepfreeze => { :frozen => 'icy'.freeze }.freeze + get :test_params, params: { + frozen: 'icy'.freeze, frozens: ['icy'.freeze].freeze, deepfreeze: { frozen: 'icy'.freeze }.freeze + } end parsed_params = eval(@response.body) assert_equal( @@ -480,8 +613,8 @@ XML end def test_params_passing_doesnt_modify_in_place - page = {:name => "Page name", :month => 4, :year => 2004, :day => 6} - get :test_params, :page => page + page = { name: "Page name", month: 4, year: 2004, day: 6 } + get :test_params, params: { page: page } assert_equal 2004, page[:year] end @@ -504,25 +637,32 @@ XML end def test_id_converted_to_string - get :test_params, :id => 20, :foo => Object.new + get :test_params, params: { + id: 20, foo: Object.new + } + assert_kind_of String, @request.path_parameters[:id] + end + + def test_deprecared_id_converted_to_string + assert_deprecated { get :test_params, id: 20, foo: Object.new} assert_kind_of String, @request.path_parameters[:id] end def test_array_path_parameter_handled_properly with_routing do |set| set.draw do - get 'file/*path', :to => 'test_case_test/test#test_params' + get 'file/*path', to: 'test_case_test/test#test_params' get ':controller/:action' end - get :test_params, :path => ['hello', 'world'] + get :test_params, params: { path: ['hello', 'world'] } assert_equal ['hello', 'world'], @request.path_parameters[:path] assert_equal 'hello/world', @request.path_parameters[:path].to_param end end def test_assert_realistic_path_parameters - get :test_params, :id => 20, :foo => Object.new + get :test_params, params: { id: 20, foo: Object.new } # All elements of path_parameters should use Symbol keys @request.path_parameters.each_key do |key| @@ -559,14 +699,37 @@ XML assert_nil @request.env['HTTP_ACCEPT'] end + def test_xhr_with_params + xhr :get, :test_params, params: { id: 1 } + + assert_equal(%({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}), @response.body) + end + + def test_xhr_with_session + xhr :get, :set_session + + assert_equal 'A wonder', session['string'], "A value stored in the session should be available by string key" + assert_equal 'A wonder', session[:string], "Test session hash should allow indifferent access" + assert_equal 'it works', session['symbol'], "Test session hash should allow indifferent access" + assert_equal 'it works', session[:symbol], "Test session hash should allow indifferent access" + end + def test_header_properly_reset_after_get_request get :test_params @request.recycle! assert_nil @request.instance_variable_get("@request_method") end + def test_deprecated_params_reset_between_post_requests + assert_deprecated { post :no_op, foo: "bar" } + assert_equal "bar", @request.params[:foo] + + post :no_op + assert @request.params[:foo].blank? + end + def test_params_reset_between_post_requests - post :no_op, :foo => "bar" + post :no_op, params: { foo: "bar" } assert_equal "bar", @request.params[:foo] post :no_op @@ -574,15 +737,15 @@ XML end def test_filtered_parameters_reset_between_requests - get :no_op, :foo => "bar" + get :no_op, params: { foo: "bar" } assert_equal "bar", @request.filtered_parameters[:foo] - get :no_op, :foo => "baz" + get :no_op, params: { foo: "baz" } assert_equal "baz", @request.filtered_parameters[:foo] end def test_path_params_reset_between_request - get :test_params, :id => "foo" + get :test_params, params: { id: "foo" } assert_equal "foo", @request.path_parameters[:id] get :test_params @@ -603,19 +766,38 @@ XML end def test_request_format - get :test_format, :format => 'html' + get :test_format, params: { format: 'html' } + assert_equal 'text/html', @response.body + + get :test_format, params: { format: 'json' } + assert_equal 'application/json', @response.body + + get :test_format, params: { format: 'xml' } + assert_equal 'application/xml', @response.body + + get :test_format assert_equal 'text/html', @response.body + end - get :test_format, :format => 'json' + def test_request_format_kwarg + get :test_format, format: 'html' + assert_equal 'text/html', @response.body + + get :test_format, format: 'json' assert_equal 'application/json', @response.body - get :test_format, :format => 'xml' + get :test_format, format: 'xml' assert_equal 'application/xml', @response.body get :test_format assert_equal 'text/html', @response.body end + def test_request_format_kwarg_overrides_params + get :test_format, format: 'json', params: { format: 'html' } + assert_equal 'application/json', @response.body + end + def test_should_have_knowledge_of_client_side_cookie_state_even_if_they_are_not_set cookies['foo'] = 'bar' get :no_op @@ -700,7 +882,10 @@ XML end def test_fixture_file_upload - post :test_file_upload, :file => fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg") + post :test_file_upload, + params: { + file: fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg") + } assert_equal '159528', @response.body end @@ -716,10 +901,21 @@ XML assert_equal File.open("#{FILES_DIR}/mona_lisa.jpg", READ_PLAIN).read, uploaded_file.read end + def test_deprecated_action_dispatch_uploaded_file_upload + filename = 'mona_lisa.jpg' + path = "#{FILES_DIR}/#{filename}" + assert_deprecated { + post :test_file_upload, file: ActionDispatch::Http::UploadedFile.new(filename: path, type: "image/jpg", tempfile: File.open(path)) + } + assert_equal '159528', @response.body + end + def test_action_dispatch_uploaded_file_upload filename = 'mona_lisa.jpg' path = "#{FILES_DIR}/#{filename}" - post :test_file_upload, :file => ActionDispatch::Http::UploadedFile.new(:filename => path, :type => "image/jpg", :tempfile => File.open(path)) + post :test_file_upload, params: { + file: ActionDispatch::Http::UploadedFile.new(filename: path, type: "image/jpg", tempfile: File.open(path)) + } assert_equal '159528', @response.body end @@ -753,7 +949,7 @@ module EngineControllerTests class BarController < ActionController::Base def index - render :text => 'bar' + render text: 'bar' end end @@ -830,7 +1026,7 @@ class NamedRoutesControllerTest < ActionController::TestCase with_routing do |set| set.draw { resources :contents } assert_equal 'http://test.host/contents/new', new_content_url - assert_equal 'http://test.host/contents/1', content_url(:id => 1) + assert_equal 'http://test.host/contents/1', content_url(id: 1) end end end @@ -839,7 +1035,7 @@ class AnonymousControllerTest < ActionController::TestCase def setup @controller = Class.new(ActionController::Base) do def index - render :text => params[:controller] + render text: params[:controller] end end.new @@ -860,29 +1056,29 @@ class RoutingDefaultsTest < ActionController::TestCase def setup @controller = Class.new(ActionController::Base) do def post - render :text => request.fullpath + render text: request.fullpath end def project - render :text => request.fullpath + render text: request.fullpath end end.new @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| r.draw do - get '/posts/:id', :to => 'anonymous#post', :bucket_type => 'post' - get '/projects/:id', :to => 'anonymous#project', :defaults => { :bucket_type => 'project' } + get '/posts/:id', to: 'anonymous#post', bucket_type: 'post' + get '/projects/:id', to: 'anonymous#project', defaults: { bucket_type: 'project' } end end end def test_route_option_can_be_passed_via_process - get :post, :id => 1, :bucket_type => 'post' + get :post, params: { id: 1, bucket_type: 'post'} assert_equal '/posts/1', @response.body end def test_route_default_is_not_required_for_building_request_uri - get :project, :id => 2 + get :project, params: { id: 2 } assert_equal '/projects/2', @response.body end end diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index 2b109ff19e..21fa670bb6 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -35,7 +35,9 @@ class WebServiceTest < ActionDispatch::IntegrationTest def test_post_json with_test_route_set do - post "/", '{"entry":{"summary":"content..."}}', 'CONTENT_TYPE' => 'application/json' + post "/", + params: '{"entry":{"summary":"content..."}}', + headers: { 'CONTENT_TYPE' => 'application/json' } assert_equal 'entry', @controller.response.body assert @controller.params.has_key?(:entry) @@ -45,7 +47,9 @@ class WebServiceTest < ActionDispatch::IntegrationTest def test_put_json with_test_route_set do - put "/", '{"entry":{"summary":"content..."}}', 'CONTENT_TYPE' => 'application/json' + put "/", + params: '{"entry":{"summary":"content..."}}', + headers: { 'CONTENT_TYPE' => 'application/json' } assert_equal 'entry', @controller.response.body assert @controller.params.has_key?(:entry) @@ -56,8 +60,9 @@ class WebServiceTest < ActionDispatch::IntegrationTest def test_register_and_use_json_simple with_test_route_set do with_params_parsers Mime::JSON => Proc.new { |data| ActiveSupport::JSON.decode(data)['request'].with_indifferent_access } do - post "/", '{"request":{"summary":"content...","title":"JSON"}}', - 'CONTENT_TYPE' => 'application/json' + post "/", + params: '{"request":{"summary":"content...","title":"JSON"}}', + headers: { 'CONTENT_TYPE' => 'application/json' } assert_equal 'summary, title', @controller.response.body assert @controller.params.has_key?(:summary) @@ -70,14 +75,16 @@ class WebServiceTest < ActionDispatch::IntegrationTest def test_use_json_with_empty_request with_test_route_set do - assert_nothing_raised { post "/", "", 'CONTENT_TYPE' => 'application/json' } + assert_nothing_raised { post "/", headers: { 'CONTENT_TYPE' => 'application/json' } } assert_equal '', @controller.response.body end end def test_dasherized_keys_as_json with_test_route_set do - post "/?full=1", '{"first-key":{"sub-key":"..."}}', 'CONTENT_TYPE' => 'application/json' + post "/?full=1", + params: '{"first-key":{"sub-key":"..."}}', + headers: { 'CONTENT_TYPE' => 'application/json' } assert_equal 'action, controller, first-key(sub-key), full', @controller.response.body assert_equal "...", @controller.params['first-key']['sub-key'] end @@ -87,7 +94,9 @@ class WebServiceTest < ActionDispatch::IntegrationTest with_test_route_set do with_params_parsers Mime::JSON => Proc.new { |data| raise Interrupt } do assert_raises(Interrupt) do - post "/", '{"title":"JSON"}}', 'CONTENT_TYPE' => 'application/json' + post "/", + params: '{"title":"JSON"}}', + headers: { 'CONTENT_TYPE' => 'application/json' } end end end diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index 1e5ed60b09..7921f05688 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -86,21 +86,21 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test 'skip diagnosis if not showing detailed exceptions' do @app = ProductionApp assert_raise RuntimeError do - get "/", {}, {'action_dispatch.show_exceptions' => true} + get "/", headers: { 'action_dispatch.show_exceptions' => true } end end test 'skip diagnosis if not showing exceptions' do @app = DevelopmentApp assert_raise RuntimeError do - get "/", {}, {'action_dispatch.show_exceptions' => false} + get "/", headers: { 'action_dispatch.show_exceptions' => false } end end test 'raise an exception on cascade pass' do @app = ProductionApp assert_raise ActionController::RoutingError do - get "/pass", {}, {'action_dispatch.show_exceptions' => true} + get "/pass", headers: { 'action_dispatch.show_exceptions' => true } end end @@ -108,14 +108,14 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest boomer = Boomer.new(false) @app = ActionDispatch::DebugExceptions.new(boomer) assert_raise ActionController::RoutingError do - get "/pass", {}, {'action_dispatch.show_exceptions' => true} + get "/pass", headers: { 'action_dispatch.show_exceptions' => true } end assert boomer.closed, "Expected to close the response body" end test 'displays routes in a table when a RoutingError occurs' do @app = DevelopmentApp - get "/pass", {}, {'action_dispatch.show_exceptions' => true} + get "/pass", headers: { 'action_dispatch.show_exceptions' => true } routing_table = body[/route_table.*<.table>/m] assert_match '/:controller(/:action)(.:format)', routing_table assert_match ':controller#:action', routing_table @@ -125,7 +125,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test 'displays request and response info when a RoutingError occurs' do @app = DevelopmentApp - get "/pass", {}, {'action_dispatch.show_exceptions' => true} + get "/pass", headers: { 'action_dispatch.show_exceptions' => true } assert_select 'h2', /Request/ assert_select 'h2', /Response/ @@ -134,27 +134,27 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "rescue with diagnostics message" do @app = DevelopmentApp - get "/", {}, {'action_dispatch.show_exceptions' => true} + get "/", headers: { 'action_dispatch.show_exceptions' => true } assert_response 500 assert_match(/puke/, body) - get "/not_found", {}, {'action_dispatch.show_exceptions' => true} + get "/not_found", headers: { 'action_dispatch.show_exceptions' => true } assert_response 404 assert_match(/#{AbstractController::ActionNotFound.name}/, body) - get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} + get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true } assert_response 405 assert_match(/ActionController::MethodNotAllowed/, body) - get "/unknown_http_method", {}, {'action_dispatch.show_exceptions' => true} + get "/unknown_http_method", headers: { 'action_dispatch.show_exceptions' => true } assert_response 405 assert_match(/ActionController::UnknownHttpMethod/, body) - get "/bad_request", {}, {'action_dispatch.show_exceptions' => true} + get "/bad_request", headers: { 'action_dispatch.show_exceptions' => true } assert_response 400 assert_match(/ActionController::BadRequest/, body) - get "/parameter_missing", {}, {'action_dispatch.show_exceptions' => true} + get "/parameter_missing", headers: { 'action_dispatch.show_exceptions' => true } assert_response 400 assert_match(/ActionController::ParameterMissing/, body) end @@ -163,38 +163,38 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest @app = DevelopmentApp xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'} - get "/", {}, xhr_request_env + get "/", headers: xhr_request_env assert_response 500 assert_no_match(/<header>/, body) assert_no_match(/<body>/, body) assert_equal "text/plain", response.content_type assert_match(/RuntimeError\npuke/, body) - get "/not_found", {}, xhr_request_env + get "/not_found", headers: xhr_request_env assert_response 404 assert_no_match(/<body>/, body) assert_equal "text/plain", response.content_type assert_match(/#{AbstractController::ActionNotFound.name}/, body) - get "/method_not_allowed", {}, xhr_request_env + get "/method_not_allowed", headers: xhr_request_env assert_response 405 assert_no_match(/<body>/, body) assert_equal "text/plain", response.content_type assert_match(/ActionController::MethodNotAllowed/, body) - get "/unknown_http_method", {}, xhr_request_env + get "/unknown_http_method", headers: xhr_request_env assert_response 405 assert_no_match(/<body>/, body) assert_equal "text/plain", response.content_type assert_match(/ActionController::UnknownHttpMethod/, body) - get "/bad_request", {}, xhr_request_env + get "/bad_request", headers: xhr_request_env assert_response 400 assert_no_match(/<body>/, body) assert_equal "text/plain", response.content_type assert_match(/ActionController::BadRequest/, body) - get "/parameter_missing", {}, xhr_request_env + get "/parameter_missing", headers: xhr_request_env assert_response 400 assert_no_match(/<body>/, body) assert_equal "text/plain", response.content_type @@ -204,8 +204,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "does not show filtered parameters" do @app = DevelopmentApp - get "/", {"foo"=>"bar"}, {'action_dispatch.show_exceptions' => true, - 'action_dispatch.parameter_filter' => [:foo]} + get "/", params: { "foo"=>"bar" }, headers: { 'action_dispatch.show_exceptions' => true, + 'action_dispatch.parameter_filter' => [:foo] } assert_response 500 assert_match(""foo"=>"[FILTERED]"", body) end @@ -213,7 +213,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "show registered original exception for wrapped exceptions" do @app = DevelopmentApp - get "/not_found_original_exception", {}, {'action_dispatch.show_exceptions' => true} + get "/not_found_original_exception", headers: { 'action_dispatch.show_exceptions' => true } assert_response 404 assert_match(/AbstractController::ActionNotFound/, body) end @@ -221,7 +221,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "named urls missing keys raise 500 level error" do @app = DevelopmentApp - get "/missing_keys", {}, {'action_dispatch.show_exceptions' => true} + get "/missing_keys", headers: { 'action_dispatch.show_exceptions' => true } assert_response 500 assert_match(/ActionController::UrlGenerationError/, body) @@ -229,7 +229,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "show the controller name in the diagnostics template when controller name is present" do @app = DevelopmentApp - get("/runtime_error", {}, { + get("/runtime_error", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.request.parameters' => { 'action' => 'show', @@ -252,7 +252,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest } } - get("/runtime_error", {}, { + get("/runtime_error", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.request.parameters' => { 'action' => 'show', @@ -267,21 +267,21 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "sets the HTTP charset parameter" do @app = DevelopmentApp - get "/", {}, {'action_dispatch.show_exceptions' => true} + get "/", headers: { 'action_dispatch.show_exceptions' => true } assert_equal "text/html; charset=utf-8", response.headers["Content-Type"] end test 'uses logger from env' do @app = DevelopmentApp output = StringIO.new - get "/", {}, {'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => Logger.new(output)} + get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => Logger.new(output) } assert_match(/puke/, output.rewind && output.read) end test 'uses backtrace cleaner from env' do @app = DevelopmentApp cleaner = stub(:clean => ['passed backtrace cleaner']) - get "/", {}, {'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => cleaner} + get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => cleaner } assert_match(/passed backtrace cleaner/, body) end @@ -294,14 +294,14 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest 'action_dispatch.logger' => Logger.new(output), 'action_dispatch.backtrace_cleaner' => backtrace_cleaner} - get "/", {}, env + get "/", headers: env assert_operator((output.rewind && output.read).lines.count, :>, 10) end test 'display backtrace when error type is SyntaxError' do @app = DevelopmentApp - get '/original_syntax_error', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new} + get '/original_syntax_error', headers: { 'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new } assert_response 500 assert_select '#Application-Trace' do @@ -312,7 +312,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test 'display backtrace on template missing errors' do @app = DevelopmentApp - get "/missing_template", nil, {} + get "/missing_template" assert_select "header h1", /Template is missing/ @@ -328,7 +328,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test 'display backtrace when error type is SyntaxError wrapped by ActionView::Template::Error' do @app = DevelopmentApp - get '/syntax_error_into_view', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new} + get '/syntax_error_into_view', headers: { 'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new } assert_response 500 assert_select '#Application-Trace' do @@ -344,7 +344,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} } end - get '/framework_raises', {}, {'action_dispatch.backtrace_cleaner' => cleaner} + get '/framework_raises', headers: { 'action_dispatch.backtrace_cleaner' => cleaner } # Assert correct error assert_response 500 diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb index d5a4d8ee11..6a439be2b5 100644 --- a/actionpack/test/dispatch/mount_test.rb +++ b/actionpack/test/dispatch/mount_test.rb @@ -64,7 +64,7 @@ class TestRoutingMount < ActionDispatch::IntegrationTest end def test_mounting_works_with_nested_script_name - get "/foo/sprockets/omg", {}, 'SCRIPT_NAME' => '/foo', 'PATH_INFO' => '/sprockets/omg' + get "/foo/sprockets/omg", headers: { 'SCRIPT_NAME' => '/foo', 'PATH_INFO' => '/sprockets/omg' } assert_equal "/foo/sprockets -- /omg", response.body end diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index b765a13fa1..d77341bc64 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -56,7 +56,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest with_test_routing do output = StringIO.new json = "[\"person]\": {\"name\": \"David\"}}" - post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => ActiveSupport::Logger.new(output)} + post "/parse", params: json, headers: { 'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => ActiveSupport::Logger.new(output) } assert_response :bad_request output.rewind && err = output.read assert err =~ /Error occurred while parsing request parameters/ @@ -79,7 +79,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest test 'raw_post is not empty for JSON request' do with_test_routing do - post '/parse', '{"posts": [{"title": "Post Title"}]}', 'CONTENT_TYPE' => 'application/json' + post '/parse', params: '{"posts": [{"title": "Post Title"}]}', headers: { 'CONTENT_TYPE' => 'application/json' } assert_equal '{"posts": [{"title": "Post Title"}]}', request.raw_post end end @@ -87,7 +87,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest private def assert_parses(expected, actual, headers = {}) with_test_routing do - post "/parse", actual, headers + post "/parse", params: actual, headers: headers assert_response :ok assert_equal(expected, TestController.last_request_parameters) end @@ -146,7 +146,7 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest private def assert_parses(expected, actual, headers = {}) with_test_routing(UsersController) do - post "/parse", actual, headers + post "/parse", params: actual, headers: headers assert_response :ok assert_equal(expected, UsersController.last_request_parameters) assert_equal(expected.merge({"action" => "parse"}), UsersController.last_parameters) diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index 926472163e..6d1b267ad2 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -37,7 +37,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest end test "parse single utf8 parameter" do - assert_equal({ 'Iñtërnâtiônà lizætiøn_name' => 'Iñtërnâtiônà lizætiøn_value'}, + assert_equal({ 'Iñtërnâtiônà lizætiøn_name' => 'Iñtërnâtiônà lizætiøn_value'}, parse_multipart('single_utf8_param'), "request.request_parameters") assert_equal( 'Iñtërnâtiônà lizætiøn_value', @@ -45,8 +45,8 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest end test "parse bracketed utf8 parameter" do - assert_equal({ 'Iñtërnâtiônà lizætiøn_name' => { - 'Iñtërnâtiônà lizætiøn_nested_name' => 'Iñtërnâtiônà lizætiøn_value'} }, + assert_equal({ 'Iñtërnâtiônà lizætiøn_name' => { + 'Iñtërnâtiônà lizætiøn_nested_name' => 'Iñtërnâtiônà lizætiøn_value'} }, parse_multipart('bracketed_utf8_param'), "request.request_parameters") assert_equal( {'Iñtërnâtiônà lizætiøn_nested_name' => 'Iñtërnâtiônà lizætiøn_value'}, @@ -134,13 +134,13 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest with_test_routing do fixture = FIXTURE_PATH + "/mona_lisa.jpg" params = { :uploaded_data => fixture_file_upload(fixture, "image/jpg") } - post '/read', params + post '/read', params: params end end test "uploads and reads file" do with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") + post '/read', params: { uploaded_data: fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") } assert_equal "File: Hello", response.body end end @@ -152,7 +152,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest get ':action', controller: 'multipart_params_parsing_test/test' end headers = { "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" } - get "/parse", {}, headers + get "/parse", headers: headers assert_response :ok end end @@ -169,7 +169,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest def parse_multipart(name) with_test_routing do headers = fixture(name) - post "/parse", headers.delete("rack.input"), headers + post "/parse", params: headers.delete("rack.input"), headers: headers assert_response :ok TestController.last_request_parameters end diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb index 50daafbb54..bc6716525e 100644 --- a/actionpack/test/dispatch/request/query_string_parsing_test.rb +++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb @@ -147,7 +147,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest get ':action', :to => ::QueryStringParsingTest::TestController end - get "/parse", nil, "QUERY_STRING" => "foo[]=bar&foo[4]=bar" + get "/parse", headers: { "QUERY_STRING" => "foo[]=bar&foo[4]=bar" } assert_response :bad_request end end @@ -162,8 +162,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest middleware.use(EarlyParse) end - - get "/parse", actual + get "/parse", params: actual assert_response :ok assert_equal(expected, ::QueryStringParsingTest::TestController.last_query_parameters) end diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index 1de05cbf09..365edf849a 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -131,7 +131,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest test "ambiguous params returns a bad request" do with_test_routing do - post "/parse", "foo[]=bar&foo[4]=bar" + post "/parse", params: "foo[]=bar&foo[4]=bar" assert_response :bad_request end end @@ -148,7 +148,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest def assert_parses(expected, actual) with_test_routing do - post "/parse", actual + post "/parse", params: actual assert_response :ok assert_equal expected, TestController.last_request_parameters assert_utf8 TestController.last_request_parameters diff --git a/actionpack/test/dispatch/request_id_test.rb b/actionpack/test/dispatch/request_id_test.rb index a8050b4fab..a307483509 100644 --- a/actionpack/test/dispatch/request_id_test.rb +++ b/actionpack/test/dispatch/request_id_test.rb @@ -41,7 +41,7 @@ class RequestIdResponseTest < ActionDispatch::IntegrationTest test "request id given on request is passed all the way to the response" do with_test_route_set do - get '/', {}, 'HTTP_X_REQUEST_ID' => 'X' * 500 + get '/', headers: { 'HTTP_X_REQUEST_ID' => 'X' * 500 } assert_equal "X" * 255, @response.headers["X-Request-Id"] end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 3373705326..3a95a9025f 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -362,22 +362,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get 'admin/passwords' => "queenbee#passwords", :constraints => ::TestRoutingMapper::IpRestrictor end - get '/admin', {}, {'REMOTE_ADDR' => '192.168.1.100'} + get '/admin', headers: { 'REMOTE_ADDR' => '192.168.1.100' } assert_equal 'queenbee#index', @response.body - get '/admin', {}, {'REMOTE_ADDR' => '10.0.0.100'} + get '/admin', headers: { 'REMOTE_ADDR' => '10.0.0.100' } assert_equal 'pass', @response.headers['X-Cascade'] - get '/admin/accounts', {}, {'REMOTE_ADDR' => '192.168.1.100'} + get '/admin/accounts', headers: { 'REMOTE_ADDR' => '192.168.1.100' } assert_equal 'queenbee#accounts', @response.body - get '/admin/accounts', {}, {'REMOTE_ADDR' => '10.0.0.100'} + get '/admin/accounts', headers: { 'REMOTE_ADDR' => '10.0.0.100' } assert_equal 'pass', @response.headers['X-Cascade'] - get '/admin/passwords', {}, {'REMOTE_ADDR' => '192.168.1.100'} + get '/admin/passwords', headers: { 'REMOTE_ADDR' => '192.168.1.100' } assert_equal 'queenbee#passwords', @response.body - get '/admin/passwords', {}, {'REMOTE_ADDR' => '10.0.0.100'} + get '/admin/passwords', headers: { 'REMOTE_ADDR' => '10.0.0.100' } assert_equal 'pass', @response.headers['X-Cascade'] end @@ -1683,9 +1683,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get '/products/0001/images/0001' assert_equal 'images#show', @response.body - get '/dashboard', {}, {'REMOTE_ADDR' => '10.0.0.100'} + get '/dashboard', headers: { 'REMOTE_ADDR' => '10.0.0.100' } assert_equal 'pass', @response.headers['X-Cascade'] - get '/dashboard', {}, {'REMOTE_ADDR' => '192.168.1.100'} + get '/dashboard', headers: { 'REMOTE_ADDR' => '192.168.1.100' } assert_equal 'dashboards#show', @response.body end @@ -3573,12 +3573,12 @@ class TestAltApp < ActionDispatch::IntegrationTest end def test_alt_request_with_matched_header - get "/", {}, "HTTP_X_HEADER" => "HEADER" + get "/", headers: { "HTTP_X_HEADER" => "HEADER" } assert_equal "XHeader", @response.body end def test_alt_request_with_unmatched_header - get "/", {}, "HTTP_X_HEADER" => "NON_MATCH" + get "/", headers: { "HTTP_X_HEADER" => "NON_MATCH" } assert_equal "Alternative App", @response.body end end @@ -3773,7 +3773,7 @@ class TestHttpMethods < ActionDispatch::IntegrationTest (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method| test "request method #{method.underscore} can be matched" do - get '/', nil, 'REQUEST_METHOD' => method + get '/', headers: { 'REQUEST_METHOD' => method } assert_equal method, @response.body end end diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index c5cd24d06e..2194efa503 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -125,7 +125,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest def test_does_set_secure_cookies_over_https with_test_route_set(:secure => true) do - get '/set_session_value', nil, 'HTTPS' => 'on' + get '/set_session_value', headers: { 'HTTPS' => 'on' } assert_response :success assert_equal "_myapp_session=#{response.body}; path=/; secure; HttpOnly", headers['Set-Cookie'] @@ -331,9 +331,11 @@ class CookieStoreTest < ActionDispatch::IntegrationTest private # Overwrite get to send SessionSecret in env hash - def get(path, parameters = nil, env = {}) - env["action_dispatch.key_generator"] ||= Generator - super + def get(path, *args) + args[0] ||= {} + args[0][:headers] ||= {} + args[0][:headers]["action_dispatch.key_generator"] ||= Generator + super(path, *args) end def with_test_route_set(options = {}) diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb index f7a06cfed4..fbd82945cc 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -172,7 +172,7 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest reset! - get '/set_session_value', :_session_id => session_id + get '/set_session_value', params: { _session_id: session_id } assert_response :success assert_not_equal session_id, cookies['_session_id'] end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 323fbc285e..72eaa916bc 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -27,30 +27,30 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest test "skip exceptions app if not showing exceptions" do @app = ProductionApp assert_raise RuntimeError do - get "/", {}, {'action_dispatch.show_exceptions' => false} + get "/", headers: { 'action_dispatch.show_exceptions' => false } end end test "rescue with error page" do @app = ProductionApp - get "/", {}, {'action_dispatch.show_exceptions' => true} + get "/", headers: { 'action_dispatch.show_exceptions' => true } assert_response 500 assert_equal "500 error fixture\n", body - get "/bad_params", {}, {'action_dispatch.show_exceptions' => true} + get "/bad_params", headers: { 'action_dispatch.show_exceptions' => true } assert_response 400 assert_equal "400 error fixture\n", body - get "/not_found", {}, {'action_dispatch.show_exceptions' => true} + get "/not_found", headers: { 'action_dispatch.show_exceptions' => true } assert_response 404 assert_equal "404 error fixture\n", body - get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} + get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true } assert_response 405 assert_equal "", body - get "/unknown_http_method", {}, {'action_dispatch.show_exceptions' => true} + get "/unknown_http_method", headers: { 'action_dispatch.show_exceptions' => true } assert_response 405 assert_equal "", body end @@ -61,11 +61,11 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest begin @app = ProductionApp - get "/", {}, {'action_dispatch.show_exceptions' => true} + get "/", headers: { 'action_dispatch.show_exceptions' => true } assert_response 500 assert_equal "500 localized error fixture\n", body - get "/not_found", {}, {'action_dispatch.show_exceptions' => true} + get "/not_found", headers: { 'action_dispatch.show_exceptions' => true } assert_response 404 assert_equal "404 error fixture\n", body ensure @@ -76,14 +76,14 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest test "sets the HTTP charset parameter" do @app = ProductionApp - get "/", {}, {'action_dispatch.show_exceptions' => true} + get "/", headers: { 'action_dispatch.show_exceptions' => true } assert_equal "text/html; charset=utf-8", response.headers["Content-Type"] end test "show registered original exception for wrapped exceptions" do @app = ProductionApp - get "/not_found_original_exception", {}, {'action_dispatch.show_exceptions' => true} + get "/not_found_original_exception", headers: { 'action_dispatch.show_exceptions' => true } assert_response 404 assert_match(/404 error/, body) end @@ -97,7 +97,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest end @app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app) - get "/not_found_original_exception", {}, {'action_dispatch.show_exceptions' => true} + get "/not_found_original_exception", headers: { 'action_dispatch.show_exceptions' => true } assert_response 404 assert_equal "YOU FAILED BRO", body end @@ -108,7 +108,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest end @app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app) - get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} + get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true } assert_response 405 assert_equal "", body end diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb index c3598c5e8e..7ced41bc2e 100644 --- a/actionpack/test/dispatch/ssl_test.rb +++ b/actionpack/test/dispatch/ssl_test.rb @@ -20,7 +20,7 @@ class SSLTest < ActionDispatch::IntegrationTest end def test_allows_https_proxy_header_url - get "http://example.org/", {}, 'HTTP_X_FORWARDED_PROTO' => "https" + get "http://example.org/", headers: { 'HTTP_X_FORWARDED_PROTO' => "https" } assert_response :success end diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index 8f79e7bf9a..ce1e1d0a6a 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -39,12 +39,12 @@ module TestUrlGeneration end test "the request's SCRIPT_NAME takes precedence over the route" do - get "/foo", {}, 'SCRIPT_NAME' => "/new", 'action_dispatch.routes' => Routes + get "/foo", headers: { 'SCRIPT_NAME' => "/new", 'action_dispatch.routes' => Routes } assert_equal "/new/foo", response.body end test "the request's SCRIPT_NAME wraps the mounted app's" do - get '/new/bar/foo', {}, 'SCRIPT_NAME' => '/new', 'PATH_INFO' => '/bar/foo', 'action_dispatch.routes' => Routes + get '/new/bar/foo', headers: { 'SCRIPT_NAME' => '/new', 'PATH_INFO' => '/bar/foo', 'action_dispatch.routes' => Routes } assert_equal "/new/bar/foo", response.body end diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb index 94f519e330..0a8842b527 100644 --- a/actionview/test/actionpack/controller/render_test.rb +++ b/actionview/test/actionpack/controller/render_test.rb @@ -957,12 +957,12 @@ class RenderTest < ActionController::TestCase end def test_accessing_params_in_template - get :accessing_params_in_template, :name => "David" + get :accessing_params_in_template, params: { name: "David" } assert_equal "Hello: David", @response.body end def test_accessing_local_assigns_in_inline_template - get :accessing_local_assigns_in_inline_template, :local_name => "Local David" + get :accessing_local_assigns_in_inline_template, params: { local_name: "Local David" } assert_equal "Goodbye, Local David", @response.body assert_equal "text/html", @response.content_type end @@ -1046,7 +1046,7 @@ class RenderTest < ActionController::TestCase end def test_accessing_params_in_template_with_layout - get :accessing_params_in_template_with_layout, :name => "David" + get :accessing_params_in_template_with_layout, params: { name: "David" } assert_equal "<html>Hello: David</html>", @response.body end diff --git a/actionview/test/template/atom_feed_helper_test.rb b/actionview/test/template/atom_feed_helper_test.rb index 9e06621c83..525d99750d 100644 --- a/actionview/test/template/atom_feed_helper_test.rb +++ b/actionview/test/template/atom_feed_helper_test.rb @@ -231,28 +231,28 @@ class AtomFeedTest < ActionController::TestCase def test_feed_should_use_default_language_if_none_is_given with_restful_routing(:scrolls) do - get :index, :id => "defaults" + get :index, params: { id: "defaults" } assert_match(%r{xml:lang="en-US"}, @response.body) end end def test_feed_should_include_two_entries with_restful_routing(:scrolls) do - get :index, :id => "defaults" + get :index, params: { id: "defaults" } assert_select "entry", 2 end end def test_entry_should_only_use_published_if_created_at_is_present with_restful_routing(:scrolls) do - get :index, :id => "defaults" + get :index, params: { id: "defaults" } assert_select "published", 1 end end def test_providing_builder_to_atom_feed with_restful_routing(:scrolls) do - get :index, :id=>"provide_builder" + get :index, params: { id: "provide_builder" } # because we pass in the non-default builder, the content generated by the # helper should go 'nowhere'. Leaving the response body blank. assert @response.body.blank? @@ -261,7 +261,7 @@ class AtomFeedTest < ActionController::TestCase def test_entry_with_prefilled_options_should_use_those_instead_of_querying_the_record with_restful_routing(:scrolls) do - get :index, :id => "entry_options" + get :index, params: { id: "entry_options" } assert_select "updated", Time.utc(2007, 1, 1).xmlschema assert_select "updated", Time.utc(2007, 1, 2).xmlschema @@ -270,21 +270,21 @@ class AtomFeedTest < ActionController::TestCase def test_self_url_should_default_to_current_request_url with_restful_routing(:scrolls) do - get :index, :id => "defaults" + get :index, params: { id: "defaults" } assert_select "link[rel=self][href=\"http://www.nextangle.com/scrolls?id=defaults\"]" end end def test_feed_id_should_be_a_valid_tag with_restful_routing(:scrolls) do - get :index, :id => "defaults" + get :index, params: { id: "defaults" } assert_select "id", :text => "tag:www.nextangle.com,2008:/scrolls?id=defaults" end end def test_entry_id_should_be_a_valid_tag with_restful_routing(:scrolls) do - get :index, :id => "defaults" + get :index, params: { id: "defaults" } assert_select "entry id", :text => "tag:www.nextangle.com,2008:Scroll/1" assert_select "entry id", :text => "tag:www.nextangle.com,2008:Scroll/2" end @@ -292,14 +292,14 @@ class AtomFeedTest < ActionController::TestCase def test_feed_should_allow_nested_xml_blocks with_restful_routing(:scrolls) do - get :index, :id => "xml_block" + get :index, params: { id: "xml_block" } assert_select "author name", :text => "DHH" end end def test_feed_should_include_atomPub_namespace with_restful_routing(:scrolls) do - get :index, :id => "feed_with_atomPub_namespace" + get :index, params: { id: "feed_with_atomPub_namespace" } assert_match %r{xml:lang="en-US"}, @response.body assert_match %r{xmlns="http://www.w3.org/2005/Atom"}, @response.body assert_match %r{xmlns:app="http://www.w3.org/2007/app"}, @response.body @@ -308,7 +308,7 @@ class AtomFeedTest < ActionController::TestCase def test_feed_should_allow_overriding_ids with_restful_routing(:scrolls) do - get :index, :id => "feed_with_overridden_ids" + get :index, params: { id: "feed_with_overridden_ids" } assert_select "id", :text => "tag:test.rubyonrails.org,2008:test/" assert_select "entry id", :text => "tag:test.rubyonrails.org,2008:1" assert_select "entry id", :text => "tag:test.rubyonrails.org,2008:2" @@ -317,7 +317,7 @@ class AtomFeedTest < ActionController::TestCase def test_feed_xml_processing_instructions with_restful_routing(:scrolls) do - get :index, :id => 'feed_with_xml_processing_instructions' + get :index, params: { id: 'feed_with_xml_processing_instructions' } assert_match %r{<\?xml-stylesheet [^\?]*type="text/css"}, @response.body assert_match %r{<\?xml-stylesheet [^\?]*href="t.css"}, @response.body end @@ -325,7 +325,7 @@ class AtomFeedTest < ActionController::TestCase def test_feed_xml_processing_instructions_duplicate_targets with_restful_routing(:scrolls) do - get :index, :id => 'feed_with_xml_processing_instructions_duplicate_targets' + get :index, params: { id: 'feed_with_xml_processing_instructions_duplicate_targets' } assert_match %r{<\?target1 (a="1" b="2"|b="2" a="1")\?>}, @response.body assert_match %r{<\?target1 (c="3" d="4"|d="4" c="3")\?>}, @response.body end @@ -333,7 +333,7 @@ class AtomFeedTest < ActionController::TestCase def test_feed_xhtml with_restful_routing(:scrolls) do - get :index, :id => "feed_with_xhtml_content" + get :index, params: { id: "feed_with_xhtml_content" } assert_match %r{xmlns="http://www.w3.org/1999/xhtml"}, @response.body assert_select "summary", :text => /Something Boring/ assert_select "summary", :text => /after 2/ @@ -342,21 +342,21 @@ class AtomFeedTest < ActionController::TestCase def test_feed_entry_type_option_default_to_text_html with_restful_routing(:scrolls) do - get :index, :id => 'defaults' + get :index, params: { id: 'defaults' } assert_select "entry link[rel=alternate][type=\"text/html\"]" end end def test_feed_entry_type_option_specified with_restful_routing(:scrolls) do - get :index, :id => 'entry_type_options' + get :index, params: { id: 'entry_type_options' } assert_select "entry link[rel=alternate][type=\"text/xml\"]" end end def test_feed_entry_url_false_option_adds_no_link with_restful_routing(:scrolls) do - get :index, :id => 'entry_url_false_option' + get :index, params: { id: 'entry_url_false_option' } assert_select "entry link", false end end diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb index 0d6f31af9b..0ce9d38fa3 100644 --- a/actionview/test/template/url_helper_test.rb +++ b/actionview/test/template/url_helper_test.rb @@ -624,13 +624,13 @@ class UrlHelperControllerTest < ActionController::TestCase end def test_named_route_url_shows_host_and_path - get :show_named_route, kind: 'url' + get :show_named_route, params: { kind: 'url' } assert_equal 'http://test.host/url_helper_controller_test/url_helper/show_named_route', @response.body end def test_named_route_path_shows_only_path - get :show_named_route, kind: 'path' + get :show_named_route, params: { kind: 'path' } assert_equal '/url_helper_controller_test/url_helper/show_named_route', @response.body end @@ -646,7 +646,7 @@ class UrlHelperControllerTest < ActionController::TestCase end end - get :show_named_route, kind: 'url' + get :show_named_route, params: { kind: 'url' } assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body end @@ -661,11 +661,11 @@ class UrlHelperControllerTest < ActionController::TestCase end def test_recall_params_should_normalize_id - get :show, id: '123' + get :show, params: { id: '123' } assert_equal 302, @response.status assert_equal 'http://test.host/url_helper_controller_test/url_helper/profile/123', @response.location - get :show, name: '123' + get :show, params: { name: '123' } assert_equal 'ok', @response.body end @@ -704,7 +704,7 @@ class LinkToUnlessCurrentWithControllerTest < ActionController::TestCase end def test_link_to_unless_current_shows_link - get :show, id: 1 + get :show, params: { id: 1 } assert_equal %{<a href="/tasks">tasks</a>\n} + %{<a href="#{@request.protocol}#{@request.host_with_port}/tasks">tasks</a>}, @response.body @@ -778,21 +778,21 @@ class PolymorphicControllerTest < ActionController::TestCase def test_existing_resource @controller = WorkshopsController.new - get :show, id: 1 + get :show, params: { id: 1 } assert_equal %{/workshops/1\n<a href="/workshops/1">Workshop</a>}, @response.body end def test_new_nested_resource @controller = SessionsController.new - get :index, workshop_id: 1 + get :index, params: { workshop_id: 1 } assert_equal %{/workshops/1/sessions\n<a href="/workshops/1/sessions">Session</a>}, @response.body end def test_existing_nested_resource @controller = SessionsController.new - get :show, workshop_id: 1, id: 1 + get :show, params: { workshop_id: 1, id: 1 } assert_equal %{/workshops/1/sessions/1\n<a href="/workshops/1/sessions/1">Session</a>}, @response.body end end diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md index 794d05d1b4..09c8f0800d 100644 --- a/activejob/CHANGELOG.md +++ b/activejob/CHANGELOG.md @@ -1,3 +1,9 @@ +* Allow keyword arguments to be used with Active Job. + + Fixes #18741. + + *Sean Griffin* + * Add `:only` option to `assert_enqueued_jobs`, to check the number of times a specific kind of job is enqueued. diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb index 752be6898e..622c37098e 100644 --- a/activejob/lib/active_job/arguments.rb +++ b/activejob/lib/active_job/arguments.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/indifferent_access' +require 'active_support/core_ext/hash' module ActiveJob # Raised when an exception is raised during job arguments deserialization. @@ -44,7 +44,9 @@ module ActiveJob private GLOBALID_KEY = '_aj_globalid'.freeze - private_constant :GLOBALID_KEY + SYMBOL_KEYS_KEY = '_aj_symbol_keys'.freeze + WITH_INDIFFERENT_ACCESS_KEY = '_aj_hash_with_indifferent_access'.freeze + private_constant :GLOBALID_KEY, :SYMBOL_KEYS_KEY, :WITH_INDIFFERENT_ACCESS_KEY def serialize_argument(argument) case argument @@ -54,10 +56,15 @@ module ActiveJob { GLOBALID_KEY => argument.to_global_id.to_s } when Array argument.map { |arg| serialize_argument(arg) } + when ActiveSupport::HashWithIndifferentAccess + result = serialize_hash(argument) + result[WITH_INDIFFERENT_ACCESS_KEY] = serialize_argument(true) + result when Hash - argument.each_with_object({}) do |(key, value), hash| - hash[serialize_hash_key(key)] = serialize_argument(value) - end + symbol_keys = argument.each_key.grep(Symbol).map(&:to_s) + result = serialize_hash(argument) + result[SYMBOL_KEYS_KEY] = symbol_keys + result else raise SerializationError.new("Unsupported argument type: #{argument.class.name}") end @@ -75,7 +82,7 @@ module ActiveJob if serialized_global_id?(argument) deserialize_global_id argument else - deserialize_hash argument + deserialize_hash(argument) end else raise ArgumentError, "Can only deserialize primitive arguments: #{argument.inspect}" @@ -90,13 +97,27 @@ module ActiveJob GlobalID::Locator.locate hash[GLOBALID_KEY] end + def serialize_hash(argument) + argument.each_with_object({}) do |(key, value), hash| + hash[serialize_hash_key(key)] = serialize_argument(value) + end + end + def deserialize_hash(serialized_hash) - serialized_hash.each_with_object({}.with_indifferent_access) do |(key, value), hash| - hash[key] = deserialize_argument(value) + result = serialized_hash.transform_values { |v| deserialize_argument(v) } + if result.delete(WITH_INDIFFERENT_ACCESS_KEY) + result = result.with_indifferent_access + elsif symbol_keys = result.delete(SYMBOL_KEYS_KEY) + result = transform_symbol_keys(result, symbol_keys) end + result end - RESERVED_KEYS = [GLOBALID_KEY, GLOBALID_KEY.to_sym] + RESERVED_KEYS = [ + GLOBALID_KEY, GLOBALID_KEY.to_sym, + SYMBOL_KEYS_KEY, SYMBOL_KEYS_KEY.to_sym, + WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_KEY.to_sym, + ] private_constant :RESERVED_KEYS def serialize_hash_key(key) @@ -109,5 +130,15 @@ module ActiveJob raise SerializationError.new("Only string and symbol hash keys may be serialized as job arguments, but #{key.inspect} is a #{key.class}") end end + + def transform_symbol_keys(hash, symbol_keys) + hash.transform_keys do |key| + if symbol_keys.include?(key) + key.to_sym + else + key + end + end + end end end diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb index d18656e398..c544e8a10f 100644 --- a/activejob/lib/active_job/test_helper.rb +++ b/activejob/lib/active_job/test_helper.rb @@ -175,9 +175,10 @@ module ActiveJob original_enqueued_jobs = enqueued_jobs.dup clear_enqueued_jobs args.assert_valid_keys(:job, :args, :at, :queue) + serialized_args = serialize_args_for_assertion(args) yield matching_job = enqueued_jobs.any? do |job| - args.all? { |key, value| value == job[key] } + serialized_args.all? { |key, value| value == job[key] } end assert matching_job, "No enqueued job found with #{args}" ensure @@ -195,9 +196,10 @@ module ActiveJob original_performed_jobs = performed_jobs.dup clear_performed_jobs args.assert_valid_keys(:job, :args, :at, :queue) + serialized_args = serialize_args_for_assertion(args) perform_enqueued_jobs { yield } matching_job = performed_jobs.any? do |job| - args.all? { |key, value| value == job[key] } + serialized_args.all? { |key, value| value == job[key] } end assert matching_job, "No performed job found with #{args}" ensure @@ -239,6 +241,14 @@ module ActiveJob enqueued_jobs.size end end + + def serialize_args_for_assertion(args) + serialized_args = args.dup + if job_args = serialized_args.delete(:args) + serialized_args[:args] = ActiveJob::Arguments.serialize(job_args) + end + serialized_args + end end end end diff --git a/activejob/test/cases/argument_serialization_test.rb b/activejob/test/cases/argument_serialization_test.rb index dbe36fc572..8b9b62190f 100644 --- a/activejob/test/cases/argument_serialization_test.rb +++ b/activejob/test/cases/argument_serialization_test.rb @@ -2,6 +2,7 @@ require 'helper' require 'active_job/arguments' require 'models/person' require 'active_support/core_ext/hash/indifferent_access' +require 'jobs/kwargs_job' class ArgumentSerializationTest < ActiveSupport::TestCase setup do @@ -31,16 +32,26 @@ class ArgumentSerializationTest < ActiveSupport::TestCase end test 'should convert records to Global IDs' do - assert_arguments_roundtrip [@person], ['_aj_globalid' => @person.to_gid.to_s] + assert_arguments_roundtrip [@person] end test 'should dive deep into arrays and hashes' do - assert_arguments_roundtrip [3, [@person]], [3, ['_aj_globalid' => @person.to_gid.to_s]] - assert_arguments_roundtrip [{ 'a' => @person }], [{ 'a' => { '_aj_globalid' => @person.to_gid.to_s }}.with_indifferent_access] + assert_arguments_roundtrip [3, [@person]] + assert_arguments_roundtrip [{ 'a' => @person }] end - test 'should stringify symbol hash keys' do - assert_equal [ 'a' => 1 ], ActiveJob::Arguments.serialize([ a: 1 ]) + test 'should maintain string and symbol keys' do + assert_arguments_roundtrip([a: 1, "b" => 2]) + end + + test 'should maintain hash with indifferent access' do + symbol_key = { a: 1 } + string_key = { 'a' => 1 } + indifferent_access = { a: 1 }.with_indifferent_access + + assert_not_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([symbol_key]).first + assert_not_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([string_key]).first + assert_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([indifferent_access]).first end test 'should disallow non-string/symbol hash keys' do @@ -71,14 +82,22 @@ class ArgumentSerializationTest < ActiveSupport::TestCase end end + test 'allows for keyword arguments' do + KwargsJob.perform_later(argument: 2) + + assert_equal "Job with argument: 2", JobBuffer.last_value + end + private def assert_arguments_unchanged(*args) - assert_arguments_roundtrip args, args + assert_arguments_roundtrip args + end + + def assert_arguments_roundtrip(args) + assert_equal args, perform_round_trip(args) end - def assert_arguments_roundtrip(args, expected_serialized_args) - serialized = ActiveJob::Arguments.serialize(args) - assert_equal expected_serialized_args, serialized - assert_equal args, ActiveJob::Arguments.deserialize(serialized) + def perform_round_trip(args) + ActiveJob::Arguments.deserialize(ActiveJob::Arguments.serialize(args)) end end diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb index f34638e7d8..0a23ae33c4 100644 --- a/activejob/test/cases/test_helper_test.rb +++ b/activejob/test/cases/test_helper_test.rb @@ -4,6 +4,7 @@ require 'active_support/core_ext/date' require 'jobs/hello_job' require 'jobs/logging_job' require 'jobs/nested_job' +require 'models/person' class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs @@ -175,6 +176,25 @@ class EnqueuedJobsTest < ActiveJob::TestCase end end end + + def test_assert_enqueued_job_with_global_id_args + ricardo = Person.new(9) + assert_enqueued_with(job: HelloJob, args: [ricardo]) do + HelloJob.perform_later(ricardo) + end + end + + def test_assert_enqueued_job_failure_with_global_id_args + ricardo = Person.new(9) + wilma = Person.new(11) + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_with(job: HelloJob, args: [wilma]) do + HelloJob.perform_later(ricardo) + end + end + + assert_equal "No enqueued job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message + end end class PerformedJobsTest < ActiveJob::TestCase @@ -282,4 +302,23 @@ class PerformedJobsTest < ActiveJob::TestCase end end end + + def test_assert_performed_job_with_global_id_args + ricardo = Person.new(9) + assert_performed_with(job: HelloJob, args: [ricardo]) do + HelloJob.perform_later(ricardo) + end + end + + def test_assert_performed_job_failure_with_global_id_args + ricardo = Person.new(9) + wilma = Person.new(11) + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_with(job: HelloJob, args: [wilma]) do + HelloJob.perform_later(ricardo) + end + end + + assert_equal "No performed job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message + end end diff --git a/activejob/test/jobs/kwargs_job.rb b/activejob/test/jobs/kwargs_job.rb new file mode 100644 index 0000000000..2df17d15ae --- /dev/null +++ b/activejob/test/jobs/kwargs_job.rb @@ -0,0 +1,7 @@ +require_relative '../support/job_buffer' + +class KwargsJob < ActiveJob::Base + def perform(argument: 1) + JobBuffer.add("Job with argument: #{argument}") + end +end diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index ca1018d399..4c78fc91a5 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -7,48 +7,46 @@ will now raise `ActiveModel::AttributeAssignment::UnknownAttributeError` instead of `NoMethodError` - ```ruby - User.new(foo: 'some value') - # => ActiveModel::AttributeAssignment::UnknownAttributeError: unknown attribute 'foo' for User. - ``` + Example: + + User.new(foo: 'some value') + # => ActiveModel::AttributeAssignment::UnknownAttributeError: unknown attribute 'foo' for User. *Eugene Gilburg* * Extracted `ActiveRecord::AttributeAssignment` to `ActiveModel::AttributeAssignment` - allowing to use it for any object as an includable module - - ``` ruby - class Cat - include ActiveModel::AttributeAssignment - attr_accessor :name, :status - end - - cat = Cat.new - cat.assign_attributes(name: "Gorby", status: "yawning") - cat.name # => 'Gorby' - cat.status => 'yawning' - cat.assign_attributes(status: "sleeping") - cat.name # => 'Gorby' - cat.status => 'sleeping' - ``` + allowing to use it for any object as an includable module. + + Example: + + class Cat + include ActiveModel::AttributeAssignment + attr_accessor :name, :status + end + + cat = Cat.new + cat.assign_attributes(name: "Gorby", status: "yawning") + cat.name # => 'Gorby' + cat.status => 'yawning' + cat.assign_attributes(status: "sleeping") + cat.name # => 'Gorby' + cat.status => 'sleeping' *Bogdan Gusiev* * Add `ActiveModel::Errors#details` To be able to return type of used validator, one can now call `details` - on Errors instance: - - ```ruby - class User < ActiveRecord::Base - validates :name, presence: true - end - ``` - - ```ruby - user = User.new; user.valid?; user.errors.details - => {name: [{error: :blank}]} - ``` + on errors instance. + + Example: + + class User < ActiveRecord::Base + validates :name, presence: true + end + + user = User.new; user.valid?; user.errors.details + => {name: [{error: :blank}]} *Wojciech WnÄ™trzak* diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 22b1c8e95b..4cc62346cb 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,29 @@ +* Fixed ActiveRecord::Relation#group method when argument is SQL reserved key word: + + Example: + + SplitTest.group(:key).count + Property.group(:value).count + + *Bogdan Gusiev* + +* Added the `#or` method on ActiveRecord::Relation, allowing use of the OR + operator to combine WHERE or HAVING clauses. + + Example: + + Post.where('id = 1').or(Post.where('id = 2')) + # => SELECT * FROM posts WHERE (id = 1) OR (id = 2) + + *Sean Griffin*, *Matthew Draper*, *Gael Muller*, *Olivier El Mekki* + +* Don't define autosave association callbacks twice from + `accepts_nested_attributes_for`. + + Fixes #18704. + + *Sean Griffin* + * Integer types will no longer raise a `RangeError` when assigning an attribute, but will instead raise when going to the database. @@ -62,7 +88,7 @@ A deprecation warning will be emitted if you have a `:time` column, and have not explicitly opted out. - Fixes #3145 + Fixes #3145. *Sean Griffin* diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 9e4a2b925c..1dc8bff193 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -104,11 +104,11 @@ module ActiveRecord end def association_key_type - @klass.column_for_attribute(association_key_name).type + @klass.type_for_attribute(association_key_name.to_s).type end def owner_key_type - @model.column_for_attribute(owner_key_name).type + @model.type_for_attribute(owner_key_name.to_s).type end def load_slices(slices) diff --git a/activerecord/lib/active_record/attribute_methods/query.rb b/activerecord/lib/active_record/attribute_methods/query.rb index dc689f399a..83b858aae7 100644 --- a/activerecord/lib/active_record/attribute_methods/query.rb +++ b/activerecord/lib/active_record/attribute_methods/query.rb @@ -15,6 +15,7 @@ module ActiveRecord when false, nil then false else column = self.class.columns_hash[attr_name] + type = self.class.type_for_attribute(attr_name) if column.nil? if Numeric === value || value !~ /[^0-9]/ !value.to_i.zero? @@ -22,7 +23,7 @@ module ActiveRecord return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value) !value.blank? end - elsif column.number? + elsif type.number? !value.zero? else !value.blank? diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index fcaaffb852..0792d19c3e 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -177,10 +177,8 @@ module ActiveRecord # before actually defining them. def add_autosave_association_callbacks(reflection) save_method = :"autosave_associated_records_for_#{reflection.name}" - validation_method = :"validate_associated_records_for_#{reflection.name}" - collection = reflection.collection? - if collection + if reflection.collection? before_save :before_save_collection_association define_non_cyclic_method(save_method) { save_collection_association(reflection) } @@ -204,8 +202,18 @@ module ActiveRecord before_save save_method end + define_autosave_validation_callbacks(reflection) + end + + def define_autosave_validation_callbacks(reflection) + validation_method = :"validate_associated_records_for_#{reflection.name}" if reflection.validate? && !method_defined?(validation_method) - method = (collection ? :validate_collection_association : :validate_single_association) + if reflection.collection? + method = :validate_collection_association + else + method = :validate_single_association + end + define_non_cyclic_method(validation_method) do send(method, reflection) # TODO: remove the following line as soon as the return value of 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 6022d0102b..c3e5e9ad61 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -286,7 +286,8 @@ module ActiveRecord columns = schema_cache.columns_hash(table_name) binds = fixture.map do |name, value| - Relation::QueryAttribute.new(name, value, columns[name].cast_type) + type = lookup_cast_type_from_column(columns[name]) + Relation::QueryAttribute.new(name, value, type) end key_list = fixture.keys.map { |name| quote_column_name(name) } value_list = prepare_binds_for_database(binds).map do |value| diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 62123cdc1f..2456376d6d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -16,7 +16,7 @@ module ActiveRecord https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11 for more information. MSG - value = column.cast_type.type_cast_for_database(value) + value = type_cast_from_column(column, value) end _quote(value) @@ -31,7 +31,7 @@ module ActiveRecord end if column - value = column.cast_type.type_cast_for_database(value) + value = type_cast_from_column(column, value) end _type_cast(value) @@ -40,6 +40,29 @@ module ActiveRecord raise TypeError, "can't cast #{value.class}#{to_type}" end + # If you are having to call this function, you are likely doing something + # wrong. The column does not have sufficient type information if the user + # provided a custom type on the class level either explicitly (via + # `attribute`) or implicitly (via `serialize`, + # `time_zone_aware_attributes`). In almost all cases, the sql type should + # only be used to change quoting behavior, when the primitive to + # represent the type doesn't sufficiently reflect the differences + # (varchar vs binary) for example. The type used to get this primitive + # should have been provided before reaching the connection adapter. + def type_cast_from_column(column, value) # :nodoc: + if column + type = lookup_cast_type_from_column(column) + type.type_cast_for_database(value) + else + value + end + end + + # See docs for +type_cast_from_column+ + def lookup_cast_type_from_column(column) # :nodoc: + lookup_cast_type(column.sql_type) + end + # Quotes a string, escaping any ' (single quote) and \ (backslash) # characters. def quote_string(s) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb index 42ea599a74..932aaf7aa7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb @@ -46,9 +46,10 @@ module ActiveRecord private def schema_default(column) - default = column.type_cast_from_database(column.default) + type = lookup_cast_type_from_column(column) + default = type.type_cast_from_database(column.default) unless default.nil? - column.type_cast_for_schema(default) + type.type_cast_for_schema(default) end end end diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index e74de60a83..a489141d1a 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -14,11 +14,7 @@ module ActiveRecord attr_reader :name, :cast_type, :null, :sql_type, :default, :default_function - delegate :type, :precision, :scale, :limit, :klass, :accessor, - :text?, :number?, :binary?, :changed?, - :type_cast_from_user, :type_cast_from_database, :type_cast_for_database, - :type_cast_for_schema, - to: :cast_type + delegate :precision, :scale, :limit, :type, to: :cast_type # Instantiates a new column in the table. # diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb index acb1278499..8f3628ec0e 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb @@ -2,17 +2,19 @@ module ActiveRecord module ConnectionAdapters # PostgreSQL-specific extensions to column definitions in a table. class PostgreSQLColumn < Column #:nodoc: - attr_reader :array + attr_reader :array, :oid, :fmod alias :array? :array - def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil) + def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil, oid = nil, fmod = nil) if sql_type =~ /\[\]$/ @array = true sql_type = sql_type[0..sql_type.length - 3] else @array = false end - super + @oid = oid + @fmod = fmod + super(name, default, cast_type, sql_type, null, default_function) end def serial? diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 9de9e2c7dc..464adb4e23 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -56,11 +56,15 @@ module ActiveRecord if column.type == :uuid && value =~ /\(\)/ value else - value = column.cast_type.type_cast_for_database(value) + value = type_cast_from_column(column, value) quote(value) end end + def lookup_cast_type_from_column(column) # :nodoc: + type_map.lookup(column.oid, column.fmod, column.sql_type) + end + private def _quote(value) 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 afd7a17c03..519a9727fb 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -183,15 +183,17 @@ module ActiveRecord def columns(table_name) # Limit, precision, and scale are all handled by the superclass. column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod| - oid = get_oid_type(oid.to_i, fmod.to_i, column_name, type) - default_value = extract_value_from_default(oid, default) + oid = oid.to_i + fmod = fmod.to_i + cast_type = get_oid_type(oid, fmod, column_name, type) + default_value = extract_value_from_default(cast_type, default) default_function = extract_default_function(default_value, default) - new_column(column_name, default_value, oid, type, notnull == 'f', default_function) + new_column(column_name, default_value, cast_type, type, notnull == 'f', default_function, oid, fmod) end end - def new_column(name, default, cast_type, sql_type = nil, null = true, default_function = nil) # :nodoc: - PostgreSQLColumn.new(name, default, cast_type, sql_type, null, default_function) + def new_column(name, default, cast_type, sql_type = nil, null = true, default_function = nil, oid = nil, fmod = nil) # :nodoc: + PostgreSQLColumn.new(name, default, cast_type, sql_type, null, default_function, oid, fmod) end # Returns the current database name. diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 225c2a8587..02a3b65934 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -50,16 +50,6 @@ module ActiveRecord end end - class SQLite3String < Type::String # :nodoc: - def type_cast_for_database(value) - if value.is_a?(::String) && value.encoding == Encoding::ASCII_8BIT - value.encode(Encoding::UTF_8, undef: :replace) - else - super - end - end - end - # The SQLite3 adapter works SQLite 3.6.16 or newer # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3). # @@ -239,6 +229,12 @@ module ActiveRecord case value when BigDecimal value.to_f + when String + if value.encoding == Encoding::ASCII_8BIT + super(value.encode(Encoding::UTF_8)) + else + super + end else super end @@ -496,7 +492,6 @@ module ActiveRecord def initialize_type_map(m) super m.register_type(/binary/i, SQLite3Binary.new) - register_class_with_limit m, %r(char)i, SQLite3String end def table_structure(table_name) diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 4705f129f2..e68b2c399c 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -210,7 +210,7 @@ module ActiveRecord elsif !connected? "#{super} (call '#{super}.connection' to establish a connection)" elsif table_exists? - attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', ' + attr_list = column_types.map { |name, type| "#{name}: #{type.type}" } * ', ' "#{super}(#{attr_list})" else "#{super}(Table doesn't exist)" diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 10e9be20b5..5b1b7fe73d 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -661,7 +661,7 @@ module ActiveRecord row[association.foreign_type] = $1 end - fk_type = association.active_record.columns_hash[fk_name].type + fk_type = association.active_record.type_for_attribute(fk_name).type row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type) end when :has_many @@ -691,7 +691,7 @@ module ActiveRecord end def primary_key_type - @association.klass.column_types[@association.klass.primary_key].type + @association.klass.type_for_attribute(@association.klass.primary_key).type end end @@ -711,7 +711,7 @@ module ActiveRecord end def primary_key_type - @primary_key_type ||= model_class && model_class.column_types[model_class.primary_key].type + @primary_key_type ||= model_class && model_class.type_for_attribute(model_class.primary_key).type end def add_join_records(rows, row, association) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 846e1162a9..117a128579 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -312,7 +312,7 @@ module ActiveRecord attr_names.each do |association_name| if reflection = _reflect_on_association(association_name) reflection.autosave = true - add_autosave_association_callbacks(reflection) + define_autosave_validation_callbacks(reflection) nested_attributes_options = self.nested_attributes_options.dup nested_attributes_options[association_name.to_sym] = options diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb index b406da14dc..63ca29305d 100644 --- a/activerecord/lib/active_record/null_relation.rb +++ b/activerecord/lib/active_record/null_relation.rb @@ -75,5 +75,9 @@ module ActiveRecord def exists?(_id = false) false end + + def or(other) + other.spawn + end end end diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index 91c9a0db99..4e597590e9 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -7,7 +7,7 @@ module ActiveRecord delegate :find_by, :find_by!, to: :all delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, to: :all delegate :find_each, :find_in_batches, to: :all - delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, + delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :or, :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :uniq, :distinct, :references, :none, :unscope, to: :all delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 83745bc169..c3c4d7f1ce 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -304,7 +304,7 @@ module ActiveRecord if association key_ids = calculated_data.collect { |row| row[group_aliases.first] } - key_records = association.klass.base_class.find(key_ids) + key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids) key_records = Hash[key_records.map { |r| [r.id, r] }] end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 0078b0f32e..7514401072 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -582,6 +582,37 @@ module ActiveRecord unscope(where: conditions.keys).where(conditions) end + # Returns a new relation, which is the logical union of this relation and the one passed as an + # argument. + # + # The two relations must be structurally compatible: they must be scoping the same model, and + # they must differ only by +where+ (if no +group+ has been defined) or +having+ (if a +group+ is + # present). Neither relation may have a +limit+, +offset+, or +uniq+ set. + # + # Post.where("id = 1").or(Post.where("id = 2")) + # # SELECT `posts`.* FROM `posts` WHERE (('id = 1' OR 'id = 2')) + # + def or(other) + spawn.or!(other) + end + + def or!(other) # :nodoc: + unless structurally_compatible_for_or?(other) + raise ArgumentError, 'Relation passed to #or must be structurally compatible' + end + + self.where_clause = self.where_clause.or(other.where_clause) + self.having_clause = self.having_clause.or(other.having_clause) + + self + end + + private def structurally_compatible_for_or?(other) # :nodoc: + Relation::SINGLE_VALUE_METHODS.all? { |m| send("#{m}_value") == other.send("#{m}_value") } && + (Relation::MULTI_VALUE_METHODS - [:extending]).all? { |m| send("#{m}_values") == other.send("#{m}_values") } && + (Relation::CLAUSE_METHODS - [:having, :where]).all? { |m| send("#{m}_clause") != other.send("#{m}_clause") } + end + # Allows to specify a HAVING clause. Note that you can't use HAVING # without also specifying a GROUP clause. # @@ -856,11 +887,11 @@ module ActiveRecord arel.having(having_clause.ast) unless having_clause.empty? arel.take(connection.sanitize_limit(limit_value)) if limit_value arel.skip(offset_value.to_i) if offset_value - arel.group(*group_values.uniq.reject(&:blank?)) unless group_values.empty? + arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty? build_order(arel) - build_select(arel, select_values.uniq) + build_select(arel) arel.distinct(distinct_value) arel.from(build_from) unless from_clause.empty? @@ -959,22 +990,24 @@ module ActiveRecord .map { |join| table.create_string_join(Arel.sql(join)) } end - def build_select(arel, selects) - if !selects.empty? - expanded_select = selects.map do |field| - if (Symbol === field || String === field) && columns_hash.key?(field.to_s) - arel_table[field] - else - field - end - end - - arel.project(*expanded_select) + def build_select(arel) + if select_values.any? + arel.project(*arel_columns(select_values.uniq)) else arel.project(@klass.arel_table[Arel.star]) end end + def arel_columns(columns) + columns.map do |field| + if (Symbol === field || String === field) && columns_hash.key?(field.to_s) + arel_table[field] + else + field + end + end + end + def reverse_sql_order(order_query) order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty? diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb index ae5667dfd6..f9b9e640ec 100644 --- a/activerecord/lib/active_record/relation/where_clause.rb +++ b/activerecord/lib/active_record/relation/where_clause.rb @@ -31,6 +31,19 @@ module ActiveRecord ) end + def or(other) + if empty? + self + elsif other.empty? + other + else + WhereClause.new( + [ast.or(other.ast)], + binds + other.binds + ) + end + end + def to_h(table_name = nil) equalities = predicates.grep(Arel::Nodes::Equality) if table_name diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index c2484d02ed..89b7e0be82 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -180,9 +180,9 @@ module ActiveRecord #:nodoc: class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc: def compute_type klass = @serializable.class - column = klass.columns_hash[name] || Type::Value.new + cast_type = klass.type_for_attribute(name) - type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name] || column.type + type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name] || cast_type.type { :text => :string, :time => :datetime }[type] || type diff --git a/activerecord/lib/active_record/type_caster/connection.rb b/activerecord/lib/active_record/type_caster/connection.rb index 1d204edb76..3878270770 100644 --- a/activerecord/lib/active_record/type_caster/connection.rb +++ b/activerecord/lib/active_record/type_caster/connection.rb @@ -8,8 +8,8 @@ module ActiveRecord def type_cast_for_database(attribute_name, value) return value if value.is_a?(Arel::Nodes::BindParam) - type = type_for(attribute_name) - type.type_cast_for_database(value) + column = column_for(attribute_name) + connection.type_cast_from_column(column, value) end protected @@ -19,17 +19,11 @@ module ActiveRecord private - def type_for(attribute_name) + def column_for(attribute_name) if connection.schema_cache.table_exists?(table_name) - column_for(attribute_name).cast_type - else - Type::Value.new + connection.schema_cache.columns_hash(table_name)[attribute_name.to_s] end end - - def column_for(attribute_name) - connection.schema_cache.columns_hash(table_name)[attribute_name.to_s] - end end end end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index f52f91e89c..8f7a46f2c7 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -59,7 +59,8 @@ module ActiveRecord end column = klass.columns_hash[attribute_name] - value = klass.type_for_attribute(attribute_name).type_cast_for_database(value) + cast_type = klass.type_for_attribute(attribute_name) + value = cast_type.type_cast_for_database(value) value = klass.connection.type_cast(value) if value.is_a?(String) && column.limit value = value.to_s[0, column.limit] @@ -67,7 +68,7 @@ module ActiveRecord value = Arel::Nodes::Quoted.new(value) - comparison = if !options[:case_sensitive] && value && column.text? + comparison = if !options[:case_sensitive] && value && cast_type.text? # will use SQL LOWER function before comparison, unless it detects a case insensitive collation klass.connection.case_insensitive_comparison(table, attribute, column, value) else diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index 331f33455e..b908b9b394 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -25,6 +25,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase end end @column = PgArray.columns_hash['tags'] + @type = PgArray.type_for_attribute("tags") end teardown do @@ -36,13 +37,14 @@ class PostgresqlArrayTest < ActiveRecord::TestCase assert_equal :string, @column.type assert_equal "character varying", @column.sql_type assert @column.array? - assert_not @column.number? - assert_not @column.binary? + assert_not @type.number? + assert_not @type.binary? ratings_column = PgArray.columns_hash['ratings'] assert_equal :integer, ratings_column.type + type = PgArray.type_for_attribute("ratings") assert ratings_column.array? - assert_not ratings_column.number? + assert_not type.number? end def test_default @@ -94,9 +96,9 @@ class PostgresqlArrayTest < ActiveRecord::TestCase end def test_type_cast_array - assert_equal(['1', '2', '3'], @column.type_cast_from_database('{1,2,3}')) - assert_equal([], @column.type_cast_from_database('{}')) - assert_equal([nil], @column.type_cast_from_database('{NULL}')) + assert_equal(['1', '2', '3'], @type.type_cast_from_database('{1,2,3}')) + assert_equal([], @type.type_cast_from_database('{}')) + assert_equal([nil], @type.type_cast_from_database('{NULL}')) end def test_type_cast_integers @@ -208,7 +210,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase x = PgArray.create!(tags: tags) x.reload - assert_equal x.tags_before_type_cast, PgArray.columns_hash['tags'].type_cast_for_database(tags) + assert_equal x.tags_before_type_cast, PgArray.type_for_attribute('tags').type_cast_for_database(tags) end def test_quoting_non_standard_delimiters diff --git a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb index f154ba4cdc..ad433b9d1b 100644 --- a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb @@ -26,18 +26,22 @@ class PostgresqlBitStringTest < ActiveRecord::TestCase column = PostgresqlBitString.columns_hash["a_bit"] assert_equal :bit, column.type assert_equal "bit(8)", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlBitString.type_for_attribute("a_bit") + assert_not type.number? + assert_not type.binary? end def test_bit_string_varying_column column = PostgresqlBitString.columns_hash["a_bit_varying"] assert_equal :bit_varying, column.type assert_equal "bit varying(4)", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlBitString.type_for_attribute("a_bit_varying") + assert_not type.number? + assert_not type.binary? end def test_default diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb index aeebec034d..99a7e88178 100644 --- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -17,6 +17,7 @@ class PostgresqlByteaTest < ActiveRecord::TestCase end end @column = ByteaDataType.columns_hash['payload'] + @type = ByteaDataType.type_for_attribute("payload") end teardown do @@ -40,16 +41,16 @@ class PostgresqlByteaTest < ActiveRecord::TestCase data = "\u001F\x8B" assert_equal('UTF-8', data.encoding.name) - assert_equal('ASCII-8BIT', @column.type_cast_from_database(data).encoding.name) + assert_equal('ASCII-8BIT', @type.type_cast_from_database(data).encoding.name) end def test_type_cast_binary_value data = "\u001F\x8B".force_encoding("BINARY") - assert_equal(data, @column.type_cast_from_database(data)) + assert_equal(data, @type.type_cast_from_database(data)) end def test_type_case_nil - assert_equal(nil, @column.type_cast_from_database(nil)) + assert_equal(nil, @type.type_cast_from_database(nil)) end def test_read_value diff --git a/activerecord/test/cases/adapters/postgresql/citext_test.rb b/activerecord/test/cases/adapters/postgresql/citext_test.rb index cfbe842948..d7e611ac46 100644 --- a/activerecord/test/cases/adapters/postgresql/citext_test.rb +++ b/activerecord/test/cases/adapters/postgresql/citext_test.rb @@ -32,9 +32,11 @@ if ActiveRecord::Base.connection.supports_extensions? column = Citext.columns_hash['cival'] assert_equal :citext, column.type assert_equal 'citext', column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = Citext.type_for_attribute('cival') + assert_not type.number? + assert_not type.binary? end def test_change_table_supports_json diff --git a/activerecord/test/cases/adapters/postgresql/composite_test.rb b/activerecord/test/cases/adapters/postgresql/composite_test.rb index 24c1969dee..be0025218e 100644 --- a/activerecord/test/cases/adapters/postgresql/composite_test.rb +++ b/activerecord/test/cases/adapters/postgresql/composite_test.rb @@ -50,9 +50,11 @@ class PostgresqlCompositeTest < ActiveRecord::TestCase column = PostgresqlComposite.columns_hash["address"] assert_nil column.type assert_equal "full_address", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlComposite.type_for_attribute("address") + assert_not type.number? + assert_not type.binary? end def test_composite_mapping @@ -111,9 +113,11 @@ class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::TestCase column = PostgresqlComposite.columns_hash["address"] assert_equal :full_address, column.type assert_equal "full_address", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlComposite.type_for_attribute("address") + assert_not type.number? + assert_not type.binary? end def test_composite_mapping diff --git a/activerecord/test/cases/adapters/postgresql/domain_test.rb b/activerecord/test/cases/adapters/postgresql/domain_test.rb index ebb04814bb..d0d70122e9 100644 --- a/activerecord/test/cases/adapters/postgresql/domain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/domain_test.rb @@ -29,9 +29,11 @@ class PostgresqlDomainTest < ActiveRecord::TestCase column = PostgresqlDomain.columns_hash["price"] assert_equal :decimal, column.type assert_equal "custom_money", column.sql_type - assert column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlDomain.type_for_attribute("price") + assert type.number? + assert_not type.binary? end def test_domain_acts_like_basetype diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb index 88b3b2cc0e..dab3f92ab2 100644 --- a/activerecord/test/cases/adapters/postgresql/enum_test.rb +++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb @@ -31,9 +31,11 @@ class PostgresqlEnumTest < ActiveRecord::TestCase column = PostgresqlEnum.columns_hash["current_mood"] assert_equal :enum, column.type assert_equal "mood", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlEnum.type_for_attribute("current_mood") + assert_not type.number? + assert_not type.binary? end def test_enum_defaults diff --git a/activerecord/test/cases/adapters/postgresql/full_text_test.rb b/activerecord/test/cases/adapters/postgresql/full_text_test.rb index e7e5d8e32a..a38291cb0a 100644 --- a/activerecord/test/cases/adapters/postgresql/full_text_test.rb +++ b/activerecord/test/cases/adapters/postgresql/full_text_test.rb @@ -21,9 +21,11 @@ class PostgresqlFullTextTest < ActiveRecord::TestCase column = Tsvector.columns_hash["text_vector"] assert_equal :tsvector, column.type assert_equal "tsvector", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = Tsvector.type_for_attribute("text_vector") + assert_not type.number? + assert_not type.binary? end def test_update_tsvector diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb index ed2bf554bb..39b8daaa83 100644 --- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb +++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb @@ -26,9 +26,11 @@ class PostgresqlPointTest < ActiveRecord::TestCase column = PostgresqlPoint.columns_hash["x"] assert_equal :point, column.type assert_equal "point", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlPoint.type_for_attribute("x") + assert_not type.number? + assert_not type.binary? end def test_default diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 2ca123409a..7ed15b2be0 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -29,6 +29,7 @@ if ActiveRecord::Base.connection.supports_extensions? end end @column = Hstore.columns_hash['tags'] + @type = Hstore.type_for_attribute("tags") end teardown do @@ -54,9 +55,10 @@ if ActiveRecord::Base.connection.supports_extensions? def test_column assert_equal :hstore, @column.type assert_equal "hstore", @column.sql_type - assert_not @column.number? - assert_not @column.binary? assert_not @column.array? + + assert_not @type.number? + assert_not @type.binary? end def test_default @@ -110,10 +112,10 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_type_cast_hstore - assert_equal({'1' => '2'}, @column.type_cast_from_database("\"1\"=>\"2\"")) - assert_equal({}, @column.type_cast_from_database("")) - assert_equal({'key'=>nil}, @column.type_cast_from_database('key => NULL')) - assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast_from_database(%q(c=>"}", "\"a\""=>"b \"a b"))) + assert_equal({'1' => '2'}, @type.type_cast_from_database("\"1\"=>\"2\"")) + assert_equal({}, @type.type_cast_from_database("")) + assert_equal({'key'=>nil}, @type.type_cast_from_database('key => NULL')) + assert_equal({'c'=>'}','"a"'=>'b "a b'}, @type.type_cast_from_database(%q(c=>"}", "\"a\""=>"b \"a b"))) end def test_with_store_accessors @@ -165,47 +167,47 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_gen1 - assert_equal(%q(" "=>""), @column.cast_type.type_cast_for_database({' '=>''})) + assert_equal(%q(" "=>""), @type.type_cast_for_database({' '=>''})) end def test_gen2 - assert_equal(%q(","=>""), @column.cast_type.type_cast_for_database({','=>''})) + assert_equal(%q(","=>""), @type.type_cast_for_database({','=>''})) end def test_gen3 - assert_equal(%q("="=>""), @column.cast_type.type_cast_for_database({'='=>''})) + assert_equal(%q("="=>""), @type.type_cast_for_database({'='=>''})) end def test_gen4 - assert_equal(%q(">"=>""), @column.cast_type.type_cast_for_database({'>'=>''})) + assert_equal(%q(">"=>""), @type.type_cast_for_database({'>'=>''})) end def test_parse1 - assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast_from_database('a=>null,b=>NuLl,c=>"NuLl",null=>c')) + assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @type.type_cast_from_database('a=>null,b=>NuLl,c=>"NuLl",null=>c')) end def test_parse2 - assert_equal({" " => " "}, @column.type_cast_from_database("\\ =>\\ ")) + assert_equal({" " => " "}, @type.type_cast_from_database("\\ =>\\ ")) end def test_parse3 - assert_equal({"=" => ">"}, @column.type_cast_from_database("==>>")) + assert_equal({"=" => ">"}, @type.type_cast_from_database("==>>")) end def test_parse4 - assert_equal({"=a"=>"q=w"}, @column.type_cast_from_database('\=a=>q=w')) + assert_equal({"=a"=>"q=w"}, @type.type_cast_from_database('\=a=>q=w')) end def test_parse5 - assert_equal({"=a"=>"q=w"}, @column.type_cast_from_database('"=a"=>q\=w')) + assert_equal({"=a"=>"q=w"}, @type.type_cast_from_database('"=a"=>q\=w')) end def test_parse6 - assert_equal({"\"a"=>"q>w"}, @column.type_cast_from_database('"\"a"=>q>w')) + assert_equal({"\"a"=>"q>w"}, @type.type_cast_from_database('"\"a"=>q>w')) end def test_parse7 - assert_equal({"\"a"=>"q\"w"}, @column.type_cast_from_database('\"a=>q"w')) + assert_equal({"\"a"=>"q\"w"}, @type.type_cast_from_database('\"a=>q"w')) end def test_rewrite diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb index f5ae872483..ba72a1fdcb 100644 --- a/activerecord/test/cases/adapters/postgresql/json_test.rb +++ b/activerecord/test/cases/adapters/postgresql/json_test.rb @@ -34,9 +34,11 @@ module PostgresqlJSONSharedTestCases column = JsonDataType.columns_hash["payload"] assert_equal column_type, column.type assert_equal column_type.to_s, column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = JsonDataType.type_for_attribute("payload") + assert_not type.number? + assert_not type.binary? end def test_default @@ -78,16 +80,16 @@ module PostgresqlJSONSharedTestCases end def test_type_cast_json - column = JsonDataType.columns_hash["payload"] + type = JsonDataType.type_for_attribute("payload") data = "{\"a_key\":\"a_value\"}" - hash = column.type_cast_from_database(data) + hash = type.type_cast_from_database(data) assert_equal({'a_key' => 'a_value'}, hash) - assert_equal({'a_key' => 'a_value'}, column.type_cast_from_database(data)) + assert_equal({'a_key' => 'a_value'}, type.type_cast_from_database(data)) - assert_equal({}, column.type_cast_from_database("{}")) - assert_equal({'key'=>nil}, column.type_cast_from_database('{"key": null}')) - assert_equal({'c'=>'}','"a"'=>'b "a b'}, column.type_cast_from_database(%q({"c":"}", "\"a\"":"b \"a b"}))) + assert_equal({}, type.type_cast_from_database("{}")) + assert_equal({'key'=>nil}, type.type_cast_from_database('{"key": null}')) + assert_equal({'c'=>'}','"a"'=>'b "a b'}, type.type_cast_from_database(%q({"c":"}", "\"a\"":"b \"a b"}))) end def test_rewrite diff --git a/activerecord/test/cases/adapters/postgresql/ltree_test.rb b/activerecord/test/cases/adapters/postgresql/ltree_test.rb index c5371348ea..cdc3269408 100644 --- a/activerecord/test/cases/adapters/postgresql/ltree_test.rb +++ b/activerecord/test/cases/adapters/postgresql/ltree_test.rb @@ -30,9 +30,11 @@ class PostgresqlLtreeTest < ActiveRecord::TestCase column = Ltree.columns_hash['path'] assert_equal :ltree, column.type assert_equal "ltree", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = Ltree.type_for_attribute('path') + assert_not type.number? + assert_not type.binary? end def test_write diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb index 78afd49b0b..ed1b7d0a1c 100644 --- a/activerecord/test/cases/adapters/postgresql/money_test.rb +++ b/activerecord/test/cases/adapters/postgresql/money_test.rb @@ -25,9 +25,11 @@ class PostgresqlMoneyTest < ActiveRecord::TestCase assert_equal :money, column.type assert_equal "money", column.sql_type assert_equal 2, column.scale - assert column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlMoney.type_for_attribute("wealth") + assert type.number? + assert_not type.binary? end def test_default @@ -46,11 +48,11 @@ class PostgresqlMoneyTest < ActiveRecord::TestCase end def test_money_type_cast - column = PostgresqlMoney.columns_hash['wealth'] - assert_equal(12345678.12, column.type_cast_from_user("$12,345,678.12")) - assert_equal(12345678.12, column.type_cast_from_user("$12.345.678,12")) - assert_equal(-1.15, column.type_cast_from_user("-$1.15")) - assert_equal(-2.25, column.type_cast_from_user("($2.25)")) + type = PostgresqlMoney.type_for_attribute('wealth') + assert_equal(12345678.12, type.type_cast_from_user("$12,345,678.12")) + assert_equal(12345678.12, type.type_cast_from_user("$12.345.678,12")) + assert_equal(-1.15, type.type_cast_from_user("-$1.15")) + assert_equal(-2.25, type.type_cast_from_user("($2.25)")) end def test_schema_dumping diff --git a/activerecord/test/cases/adapters/postgresql/network_test.rb b/activerecord/test/cases/adapters/postgresql/network_test.rb index 741876d3ca..cb75faa1e5 100644 --- a/activerecord/test/cases/adapters/postgresql/network_test.rb +++ b/activerecord/test/cases/adapters/postgresql/network_test.rb @@ -23,27 +23,33 @@ class PostgresqlNetworkTest < ActiveRecord::TestCase column = PostgresqlNetworkAddress.columns_hash["cidr_address"] assert_equal :cidr, column.type assert_equal "cidr", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlNetworkAddress.type_for_attribute("cidr_address") + assert_not type.number? + assert_not type.binary? end def test_inet_column column = PostgresqlNetworkAddress.columns_hash["inet_address"] assert_equal :inet, column.type assert_equal "inet", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlNetworkAddress.type_for_attribute("inet_address") + assert_not type.number? + assert_not type.binary? end def test_macaddr_column column = PostgresqlNetworkAddress.columns_hash["mac_address"] assert_equal :macaddr, column.type assert_equal "macaddr", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = PostgresqlNetworkAddress.type_for_attribute("mac_address") + assert_not type.number? + assert_not type.binary? end def test_network_types diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index d328f17a3f..ad86d617b8 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -49,9 +49,11 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase column = UUIDType.columns_hash["guid"] assert_equal :uuid, column.type assert_equal "uuid", column.sql_type - assert_not column.number? - assert_not column.binary? assert_not column.array? + + type = UUIDType.type_for_attribute("guid") + assert_not type.number? + assert_not type.binary? end def test_treat_blank_uuid_as_nil diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb index 274e358e4a..c1d9b7c273 100644 --- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb @@ -85,7 +85,7 @@ module ActiveRecord def test_quoting_binary_strings value = "hello".encode('ascii-8bit') - type = SQLite3String.new + type = Type::String.new assert_equal "'hello'", @conn.quote(type.type_cast_for_database(value)) end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 52765881d0..859afc4553 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -1061,11 +1061,16 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_not_ignore_different_error_messages_on_the_same_attribute + old_validators = Ship._validators.deep_dup + old_callbacks = Ship._validate_callbacks.deep_dup Ship.validates_format_of :name, :with => /\w/ @pirate.ship.name = "" @pirate.catchphrase = nil assert @pirate.invalid? assert_equal ["can't be blank", "is invalid"], @pirate.errors[:"ship.name"] + ensure + Ship._validators = old_validators if old_validators + Ship._validate_callbacks = old_callbacks if old_callbacks end def test_should_still_allow_to_bypass_validations_on_the_associated_model diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 299217214e..f47568f2f5 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -631,4 +631,9 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal({ "has trinket" => part.id }, ShipPart.joins(:trinkets).group("ship_parts.name").sum(:id)) end + + def test_calculation_grouped_by_association_doesnt_error_when_no_records_have_association + Client.update_all(client_of: nil) + assert_equal({ nil => Client.count }, Client.group(:firm).count) + end end diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb index a4bff0cbb9..3cd4073a38 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -68,8 +68,8 @@ module ActiveRecord five = columns.detect { |c| c.name == "five" } unless mysql assert_equal "hello", one.default - assert_equal true, two.type_cast_from_database(two.default) - assert_equal false, three.type_cast_from_database(three.default) + assert_equal true, connection.lookup_cast_type_from_column(two).type_cast_from_database(two.default) + assert_equal false, connection.lookup_cast_type_from_column(three).type_cast_from_database(three.default) assert_equal '1', four.default assert_equal "hello", five.default unless mysql end diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb index e6aa901814..54d3a729c3 100644 --- a/activerecord/test/cases/migration/columns_test.rb +++ b/activerecord/test/cases/migration/columns_test.rb @@ -196,7 +196,7 @@ module ActiveRecord old_columns = connection.columns(TestModel.table_name) assert old_columns.find { |c| - default = c.type_cast_from_database(c.default) + default = connection.lookup_cast_type_from_column(c).type_cast_from_database(c.default) c.name == 'approved' && c.type == :boolean && default == true } @@ -204,11 +204,11 @@ module ActiveRecord new_columns = connection.columns(TestModel.table_name) assert_not new_columns.find { |c| - default = c.type_cast_from_database(c.default) + default = connection.lookup_cast_type_from_column(c).type_cast_from_database(c.default) c.name == 'approved' and c.type == :boolean and default == true } assert new_columns.find { |c| - default = c.type_cast_from_database(c.default) + default = connection.lookup_cast_type_from_column(c).type_cast_from_database(c.default) c.name == 'approved' and c.type == :boolean and default == false } change_column :test_models, :approved, :boolean, :default => true diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 8bc42b8890..198cd6f341 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -1037,4 +1037,21 @@ class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveR ShipPart.create!(:ship => @ship, :name => "Stern") assert_no_queries { @ship.valid? } end + + test "circular references do not perform unnecessary queries" do + ship = Ship.new(name: "The Black Rock") + part = ship.parts.build(name: "Stern") + ship.treasures.build(looter: part) + + assert_queries 3 do + ship.save! + end + end + + test "nested singular associations are validated" do + part = ShipPart.new(name: "Stern", ship_attributes: { name: nil }) + + assert_not part.valid? + assert_equal ["Ship name can't be blank"], part.errors.full_messages + end end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index a2252a836f..b0e40c7145 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -86,18 +86,15 @@ class ReflectionTest < ActiveRecord::TestCase assert_equal "attribute_that_doesnt_exist", column.name assert_equal nil, column.sql_type assert_equal nil, column.type - assert_not column.number? - assert_not column.text? - assert_not column.binary? end - def test_non_existent_columns_are_identity_types - column = @first.column_for_attribute("attribute_that_doesnt_exist") + def test_non_existent_types_are_identity_types + type = @first.type_for_attribute("attribute_that_doesnt_exist") object = Object.new - assert_equal object, column.type_cast_from_database(object) - assert_equal object, column.type_cast_from_user(object) - assert_equal object, column.type_cast_for_database(object) + assert_equal object, type.type_cast_from_database(object) + assert_equal object, type.type_cast_from_user(object) + assert_equal object, type.type_cast_for_database(object) end def test_reflection_klass_for_nested_class_name diff --git a/activerecord/test/cases/relation/or_test.rb b/activerecord/test/cases/relation/or_test.rb new file mode 100644 index 0000000000..2006fc9611 --- /dev/null +++ b/activerecord/test/cases/relation/or_test.rb @@ -0,0 +1,84 @@ +require "cases/helper" +require 'models/post' + +module ActiveRecord + class OrTest < ActiveRecord::TestCase + fixtures :posts + + def test_or_with_relation + expected = Post.where('id = 1 or id = 2').to_a + assert_equal expected, Post.where('id = 1').or(Post.where('id = 2')).to_a + end + + def test_or_identity + expected = Post.where('id = 1').to_a + assert_equal expected, Post.where('id = 1').or(Post.where('id = 1')).to_a + end + + def test_or_with_null_left + expected = Post.where('id = 1').to_a + assert_equal expected, Post.none.or(Post.where('id = 1')).to_a + end + + def test_or_with_null_right + expected = Post.where('id = 1').to_a + assert_equal expected, Post.where('id = 1').or(Post.none).to_a + end + + def test_or_with_bind_params + assert_equal Post.find([1, 2]), Post.where(id: 1).or(Post.where(id: 2)).to_a + end + + def test_or_with_null_both + expected = Post.none.to_a + assert_equal expected, Post.none.or(Post.none).to_a + end + + def test_or_without_left_where + expected = Post.all + assert_equal expected, Post.or(Post.where('id = 1')).to_a + end + + def test_or_without_right_where + expected = Post.all + assert_equal expected, Post.where('id = 1').or(Post.all).to_a + end + + def test_or_preserves_other_querying_methods + expected = Post.where('id = 1 or id = 2 or id = 3').order('body asc').to_a + partial = Post.order('body asc') + assert_equal expected, partial.where('id = 1').or(partial.where(:id => [2, 3])).to_a + assert_equal expected, Post.order('body asc').where('id = 1').or(Post.order('body asc').where(:id => [2, 3])).to_a + end + + def test_or_with_incompatible_relations + assert_raises ArgumentError do + Post.order('body asc').where('id = 1').or(Post.order('id desc').where(:id => [2, 3])).to_a + end + end + + def test_or_when_grouping + groups = Post.where('id < 10').group('body').select('body, COUNT(*) AS c') + expected = groups.having("COUNT(*) > 1 OR body like 'Such%'").to_a.map {|o| [o.body, o.c] } + assert_equal expected, groups.having('COUNT(*) > 1').or(groups.having("body like 'Such%'")).to_a.map {|o| [o.body, o.c] } + end + + def test_or_with_named_scope + expected = Post.where("id = 1 or body LIKE '\%a\%'").to_a + assert_equal expected, Post.where('id = 1').or(Post.containing_the_letter_a) + end + + def test_or_inside_named_scope + expected = Post.where("body LIKE '\%a\%' OR title LIKE ?", "%'%").order('id DESC').to_a + assert_equal expected, Post.order(id: :desc).typographically_interesting + end + + def test_or_on_loaded_relation + expected = Post.where('id = 1 or id = 2').to_a + p = Post.where('id = 1') + p.load + assert_equal p.loaded?, true + assert_equal expected, p.or(Post.where('id = 2')).to_a + end + end +end diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb index db18980e0b..c20ed94d90 100644 --- a/activerecord/test/cases/relation/where_clause_test.rb +++ b/activerecord/test/cases/relation/where_clause_test.rb @@ -145,6 +145,26 @@ class ActiveRecord::Relation assert_equal where_clause.ast, where_clause_with_empty.ast end + test "or joins the two clauses using OR" do + where_clause = WhereClause.new([table["id"].eq(bind_param)], [attribute("id", 1)]) + other_clause = WhereClause.new([table["name"].eq(bind_param)], [attribute("name", "Sean")]) + expected_ast = + Arel::Nodes::Grouping.new( + Arel::Nodes::Or.new(table["id"].eq(bind_param), table["name"].eq(bind_param)) + ) + expected_binds = where_clause.binds + other_clause.binds + + assert_equal expected_ast.to_sql, where_clause.or(other_clause).ast.to_sql + assert_equal expected_binds, where_clause.or(other_clause).binds + end + + test "or returns an empty where clause when either side is empty" do + where_clause = WhereClause.new([table["id"].eq(bind_param)], [attribute("id", 1)]) + + assert_equal WhereClause.empty, where_clause.or(WhereClause.empty) + assert_equal WhereClause.empty, WhereClause.empty.or(where_clause) + end + private def table diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 8eb65d39ca..5c5ab499a0 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -16,6 +16,7 @@ require 'models/engine' require 'models/tyre' require 'models/minivan' require 'models/aircraft' +require "models/possession" class RelationTest < ActiveRecord::TestCase @@ -1482,6 +1483,10 @@ class RelationTest < ActiveRecord::TestCase assert_equal [post], having_then_where end + def test_grouping_by_column_with_reserved_name + assert_equal [], Possession.select(:where).group(:where).to_a + end + def test_references_triggers_eager_loading scope = Post.includes(:comments) assert !scope.eager_loading? diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 7b637c9e3f..052b1c9690 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -18,6 +18,7 @@ class Post < ActiveRecord::Base end scope :containing_the_letter_a, -> { where("body LIKE '%a%'") } + scope :titled_with_an_apostrophe, -> { where("title LIKE '%''%'") } scope :ranked_by_comments, -> { order("comments_count DESC") } scope :limit_by, lambda {|l| limit(l) } @@ -43,6 +44,8 @@ class Post < ActiveRecord::Base scope :tagged_with, ->(id) { joins(:taggings).where(taggings: { tag_id: id }) } scope :tagged_with_comment, ->(comment) { joins(:taggings).where(taggings: { comment: comment }) } + scope :typographically_interesting, -> { containing_the_letter_a.or(titled_with_an_apostrophe) } + has_many :comments do def find_most_recent order("id DESC").first diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb index c2f6d492d8..312caef604 100644 --- a/activerecord/test/models/ship.rb +++ b/activerecord/test/models/ship.rb @@ -4,6 +4,7 @@ class Ship < ActiveRecord::Base belongs_to :pirate belongs_to :update_only_pirate, :class_name => 'Pirate' has_many :parts, :class_name => 'ShipPart' + has_many :treasures accepts_nested_attributes_for :parts, :allow_destroy => true accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc(&:empty?) diff --git a/activerecord/test/models/ship_part.rb b/activerecord/test/models/ship_part.rb index b6a8a506b4..05c65f8a4a 100644 --- a/activerecord/test/models/ship_part.rb +++ b/activerecord/test/models/ship_part.rb @@ -2,6 +2,7 @@ class ShipPart < ActiveRecord::Base belongs_to :ship has_many :trinkets, :class_name => "Treasure", :as => :looter accepts_nested_attributes_for :trinkets, :allow_destroy => true + accepts_nested_attributes_for :ship validates_presence_of :name -end
\ No newline at end of file +end diff --git a/activerecord/test/models/treasure.rb b/activerecord/test/models/treasure.rb index a69d3fd3df..ffc65466d5 100644 --- a/activerecord/test/models/treasure.rb +++ b/activerecord/test/models/treasure.rb @@ -1,6 +1,7 @@ class Treasure < ActiveRecord::Base has_and_belongs_to_many :parrots belongs_to :looter, :polymorphic => true + belongs_to :ship has_many :price_estimates, :as => :estimate_of has_and_belongs_to_many :rich_people, join_table: 'peoples_treasures', validate: false diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 21b23d8e0c..1add85cc05 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -772,6 +772,7 @@ ActiveRecord::Schema.define do t.column :type, :string t.column :looter_id, :integer t.column :looter_type, :string + t.belongs_to :ship end create_table :tyres, force: true do |t| diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index f597bc9104..367e857d27 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,11 @@ +* Add `file_fixture` to `ActiveSupport::TestCase`. + It provides a simple mechanism to access sample files in your test cases. + + By default file fixtures are stored in `test/fixtures/files`. This can be + configured per test-case using the `file_fixture_path` class attribute. + + *Yves Senn* + * Return value of yielded block in `File.atomic_write`. *Ian Ker-Seymer* diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index e03e7c30d8..664cc15a29 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -373,7 +373,7 @@ module ActiveSupport #:nodoc: # Is the provided constant path defined? def qualified_const_defined?(path) - Object.qualified_const_defined?(path.sub(/^::/, ''), false) + Object.const_defined?(path, false) end # Given +path+, a filesystem path to a ruby file, return an array of @@ -607,7 +607,7 @@ module ActiveSupport #:nodoc: def autoloaded?(desc) return false if desc.is_a?(Module) && desc.anonymous? name = to_constant_name desc - return false unless qualified_const_defined? name + return false unless qualified_const_defined?(name) return autoloaded_constants.include?(name) end diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index c7d6c62129..739823bd56 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -8,6 +8,7 @@ require 'active_support/testing/declarative' require 'active_support/testing/isolation' require 'active_support/testing/constant_lookup' require 'active_support/testing/time_helpers' +require 'active_support/testing/file_fixtures' require 'active_support/core_ext/kernel/reporting' module ActiveSupport @@ -55,6 +56,7 @@ module ActiveSupport include ActiveSupport::Testing::Assertions include ActiveSupport::Testing::Deprecation include ActiveSupport::Testing::TimeHelpers + include ActiveSupport::Testing::FileFixtures extend ActiveSupport::Testing::Declarative # test/unit backwards compatibility methods diff --git a/activesupport/lib/active_support/testing/file_fixtures.rb b/activesupport/lib/active_support/testing/file_fixtures.rb new file mode 100644 index 0000000000..4c6a0801b8 --- /dev/null +++ b/activesupport/lib/active_support/testing/file_fixtures.rb @@ -0,0 +1,34 @@ +module ActiveSupport + module Testing + # Adds simple access to sample files called file fixtures. + # File fixtures are normal files stored in + # <tt>ActiveSupport::TestCase.file_fixture_path</tt>. + # + # File fixtures are represented as +Pathname+ objects. + # This makes it easy to extract specific information: + # + # file_fixture("example.txt").read # get the file's content + # file_fixture("example.mp3").size # get the file size + module FileFixtures + extend ActiveSupport::Concern + + included do + class_attribute :file_fixture_path, instance_writer: false + end + + # Returns a +Pathname+ to the fixture file named +fixture_name+. + # + # Raises ArgumentError if +fixture_name+ can't be found. + def file_fixture(fixture_name) + path = Pathname.new(File.join(file_fixture_path, fixture_name)) + + if path.exist? + path + else + msg = "the directory '%s' does not contain a file named '%s'" + raise ArgumentError, msg % [file_fixture_path, fixture_name] + end + end + end + end +end diff --git a/activesupport/test/file_fixtures/sample.txt b/activesupport/test/file_fixtures/sample.txt new file mode 100644 index 0000000000..0fa80e7383 --- /dev/null +++ b/activesupport/test/file_fixtures/sample.txt @@ -0,0 +1 @@ +sample file fixture diff --git a/activesupport/test/testing/file_fixtures_test.rb b/activesupport/test/testing/file_fixtures_test.rb new file mode 100644 index 0000000000..91b8a9071c --- /dev/null +++ b/activesupport/test/testing/file_fixtures_test.rb @@ -0,0 +1,28 @@ +require 'abstract_unit' + +class FileFixturesTest < ActiveSupport::TestCase + self.file_fixture_path = File.expand_path("../../file_fixtures", __FILE__) + + test "#file_fixture returns Pathname to file fixture" do + path = file_fixture("sample.txt") + assert_kind_of Pathname, path + assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s + end + + test "raises an exception when the fixture file does not exist" do + e = assert_raises(ArgumentError) do + file_fixture("nope") + end + assert_match(/^the directory '[^']+test\/file_fixtures' does not contain a file named 'nope'$/, e.message) + end +end + +class FileFixturesPathnameDirectoryTest < ActiveSupport::TestCase + self.file_fixture_path = Pathname.new(File.expand_path("../../file_fixtures", __FILE__)) + + test "#file_fixture_path returns Pathname to file fixture" do + path = file_fixture("sample.txt") + assert_kind_of Pathname, path + assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s + end +end diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md index cd3fa9f65b..99d69d5eda 100644 --- a/guides/CHANGELOG.md +++ b/guides/CHANGELOG.md @@ -1,3 +1,7 @@ +* New section in Active Record Association Basics: Single Table Inheritance + + *Andrey Nering* + * New section in Active Record Querying: Understanding The Method Chaining *Andrey Nering* diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index 97cabc1728..b8db21a989 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -479,7 +479,8 @@ Rails will generate a name for every foreign key starting with There is a `:name` option to specify a different name if needed. NOTE: Active Record only supports single column foreign keys. `execute` and -`structure.sql` are required to use composite foreign keys. +`structure.sql` are required to use composite foreign keys. See +[Schema Dumping and You](#schema-dumping-and-you). Removing a foreign key is easy as well: @@ -695,6 +696,10 @@ of `create_table` and `reversible`, replacing `create_table` by `drop_table`, and finally replacing `up` by `down` and vice-versa. This is all taken care of by `revert`. +NOTE: If you want to add check constraints like in the examples above, +you will have to use `structure.sql` as dump method. See +[Schema Dumping and You](#schema-dumping-and-you). + Running Migrations ------------------ @@ -943,10 +948,10 @@ that Active Record supports. This could be very useful if you were to distribute an application that is able to run against multiple databases. There is however a trade-off: `db/schema.rb` cannot express database specific -items such as triggers, or stored procedures. While in a migration you can -execute custom SQL statements, the schema dumper cannot reconstitute those -statements from the database. If you are using features like this, then you -should set the schema format to `:sql`. +items such as triggers, stored procedures or check constraints. While in a +migration you can execute custom SQL statements, the schema dumper cannot +reconstitute those statements from the database. If you are using features like +this, then you should set the schema format to `:sql`. Instead of using Active Record's schema dumper, the database's structure will be dumped using a tool specific to the database (via the `db:structure:dump` diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index dab885a8fb..8633cc4f10 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -2243,3 +2243,67 @@ Extensions can refer to the internals of the association proxy using these three * `proxy_association.owner` returns the object that the association is a part of. * `proxy_association.reflection` returns the reflection object that describes the association. * `proxy_association.target` returns the associated object for `belongs_to` or `has_one`, or the collection of associated objects for `has_many` or `has_and_belongs_to_many`. + +Single Table Inheritance +------------------------ + +Sometimes, you may want to share fields and behavior between different models. +Let's say we have Car, Motorcycle and Bicycle models. We will want to share +the `color` and `price` fields and some methods for all of them, but having some +specific behavior for each, and separated controllers too. + +Rails makes this quite easy. First, let's generate the base Vehicle model: + +```bash +$ rails generate model vehicle type:string color:string price:decimal{10.2} +``` + +Did you note we are adding a "type" field? Since all models will be saved in a +single database table, Rails will save in this column the name of the model that +is being saved. In our example, this can be "Car", "Motorcycle" or "Bicycle." +STI won't work without a "type" field in the table. + +Next, we will generate the three models that inherit from Vehicle. For this, +we can use the `--parent=PARENT` option, which will generate a model that +inherits from the specified parent and without equivalent migration (since the +table already exists). + +For example, to generate the Car model: + +```bash +$ rails generate model car --parent=Vehicle +``` + +The generated model will look like this: + +```ruby +class Car < Vehicle +end +``` + +This means that all behavior added to Vehicle is available for Car too, as +associations, public methods, etc. + +Creating a car will save it in the `vehicles` table with "Car" as the `type` field: + +```ruby +Car.create color: 'Red', price: 10000 +``` + +will generate the following SQL: + +```sql +INSERT INTO "vehicles" ("type", "color", "price") VALUES ("Car", "Red", 10000) +``` + +Querying car records will just search for vehicles that are cars: + +```ruby +Car.all +``` + +will run a query like: + +```sql +SELECT "vehicles".* FROM "vehicles" WHERE "vehicles"."type" IN ('Car') +``` diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md index 51c46d707c..f0ef03f0ce 100644 --- a/guides/source/autoloading_and_reloading_constants.md +++ b/guides/source/autoloading_and_reloading_constants.md @@ -324,7 +324,7 @@ relative: `::Billing::Invoice`. That would force `Billing` to be looked up only as a top-level constant. `Invoice` on the other hand is qualified by `Billing` and we are going to see -its resolution next. Let's call *parent* to that qualifying class or module +its resolution next. Let's define *parent* to be that qualifying class or module object, that is, `Billing` in the example above. The algorithm for qualified constants goes like this: diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 7381521658..e06706d750 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -173,6 +173,14 @@ $ git checkout -b my_new_branch It doesn't matter much what name you use, because this branch will only exist on your local computer and your personal repository on GitHub. It won't be part of the Rails Git repository. +### Bundle Update + +Update and install the required gems. + +```bash +$ bundle update +``` + ### Running an Application Against Your Local Branch In case you need a dummy Rails app to test changes, the `--dev` flag of `rails new` generates an application that uses your local branch: diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 4c02c99cc7..90004c611b 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -687,7 +687,14 @@ class LabellingFormBuilder < ActionView::Helpers::FormBuilder end ``` -If you reuse this frequently you could define a `labeled_form_for` helper that automatically applies the `builder: LabellingFormBuilder` option. +If you reuse this frequently you could define a `labeled_form_for` helper that automatically applies the `builder: LabellingFormBuilder` option: + +```ruby +def labeled_form_for(record, options = {}, &block) + options.merge! builder: LabellingFormBuilder + form_for record, options, &block +end +``` The form builder used also determines what happens when you do diff --git a/guides/source/testing.md b/guides/source/testing.md index fa55c09c64..a083b3f981 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -480,21 +480,28 @@ In the `test_should_get_index` test, Rails simulates a request on the action cal The `get` method kicks off the web request and populates the results into the response. It accepts 4 arguments: -* The action of the controller you are requesting. This can be in the form of a string or a symbol. -* An optional hash of request parameters to pass into the action (eg. query string parameters or article variables). -* An optional hash of session variables to pass along with the request. -* An optional hash of flash values. +* The action of the controller you are requesting. + This can be in the form of a string or a symbol. + +* `params`: option with a hash of request parameters to pass into the action + (e.g. query string parameters or article variables). + +* `session`: option with a hash of session variables to pass along with the request. + +* `flash`: option with a hash of flash values. + +All the keyword arguments are optional. Example: Calling the `:show` action, passing an `id` of 12 as the `params` and setting a `user_id` of 5 in the session: ```ruby -get(:show, {'id' => "12"}, {'user_id' => 5}) +get(:show, params: { 'id' => "12" }, session: { 'user_id' => 5 }) ``` Another example: Calling the `:view` action, passing an `id` of 12 as the `params`, this time with no session, but with a flash message. ```ruby -get(:view, {'id' => '12'}, nil, {'message' => 'booya!'}) +get(:view, params: { 'id' => '12' }, flash: { 'message' => 'booya!' }) ``` NOTE: If you try running `test_should_create_article` test from `articles_controller_test.rb` it will fail on account of the newly added model level validation and rightly so. @@ -504,7 +511,7 @@ Let us modify `test_should_create_article` test in `articles_controller_test.rb` ```ruby test "should create article" do assert_difference('Article.count') do - post :create, article: {title: 'Some title'} + post :create, params: { article: { title: 'Some title' } } end assert_redirected_to article_path(assigns(:article)) @@ -534,7 +541,7 @@ NOTE: Functional tests do not verify whether the specified request type is accep ```ruby test "ajax request responds with no layout" do - xhr :get, :show, id: articles(:first).id + xhr :get, :show, params: { id: articles(:first).id } assert_template :index assert_template layout: nil @@ -638,7 +645,7 @@ Let's start by adding this assertion to our `test_should_create_article` test: ```ruby test "should create article" do assert_difference('Article.count') do - post :create, article: {title: 'Some title'} + post :create, params: { article: { title: 'Some title' } } end assert_redirected_to article_path(assigns(:article)) @@ -708,7 +715,7 @@ Let's write a test for the `:show` action: ```ruby test "should show article" do article = articles(:one) - get :show, id: article.id + get :show, params: { id: article.id } assert_response :success end ``` @@ -721,7 +728,7 @@ How about deleting an existing Article? test "should destroy article" do article = articles(:one) assert_difference('Article.count', -1) do - delete :destroy, id: article.id + delete :destroy, params: { id: article.id } end assert_redirected_to articles_path @@ -733,7 +740,7 @@ We can also add a test for updating an existing Article. ```ruby test "should update article" do article = articles(:one) - patch :update, id: article.id, article: {title: "updated"} + patch :update, params: { id: article.id, article: { title: "updated" } } assert_redirected_to article_path(assigns(:article)) end ``` @@ -759,20 +766,20 @@ class ArticlesControllerTest < ActionController::TestCase test "should show article" do # Reuse the @article instance variable from setup - get :show, id: @article.id + get :show, params: { id: @article.id } assert_response :success end test "should destroy article" do assert_difference('Article.count', -1) do - delete :destroy, id: @article.id + delete :destroy, params: { id: @article.id } end assert_redirected_to articles_path end test "should update article" do - patch :update, id: @article.id, article: {title: "updated"} + patch :update, params: { id: @article.id, article: { title: "updated" } } assert_redirected_to article_path(assigns(:article)) end end @@ -1026,7 +1033,8 @@ test "can create an article" do assert_response :success assert_template "articles/new", partial: "articles/_form" - post "/articles", article: {title: "can create", body: "article successfully."} + post "/articles", + params: { article: { title: "can create", body: "article successfully." } } assert_response :redirect follow_redirect! assert_response :success @@ -1042,7 +1050,8 @@ We start by calling the `:new` action on our Articles controller. This response After this we make a post request to the `:create` action of our Articles controller: ```ruby -post "/articles", article: {title: "can create", body: "article successfully."} +post "/articles", + params: { article: { title: "can create", body: "article successfully." } } assert_response :redirect follow_redirect! ``` @@ -1147,7 +1156,7 @@ require 'test_helper' class UserControllerTest < ActionController::TestCase test "invite friend" do assert_difference 'ActionMailer::Base.deliveries.size', +1 do - post :invite_friend, email: 'friend@example.com' + post :invite_friend, params: { email: 'friend@example.com' } end invite_email = ActionMailer::Base.deliveries.last diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 30b86db8bb..90aa831f74 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,7 @@ +* Rename `--skip-test-unit` option to `--skip-test` in app generator + + *Melanie Gilman* + * Add the `method_source` gem to the default Gemfile for apps *Sean Griffin* diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 71186891a3..4c53248762 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -69,8 +69,8 @@ module Rails class_option :skip_turbolinks, type: :boolean, default: false, desc: 'Skip turbolinks gem' - class_option :skip_test_unit, type: :boolean, aliases: '-T', default: false, - desc: 'Skip Test::Unit files' + class_option :skip_test, type: :boolean, aliases: '-T', default: false, + desc: 'Skip test files' class_option :rc, type: :string, default: false, desc: "Path to file containing extra configuration options for rails command" @@ -168,7 +168,7 @@ module Rails end def include_all_railties? - options.values_at(:skip_active_record, :skip_action_mailer, :skip_test_unit, :skip_sprockets).none? + options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets).none? end def comment_if(value) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 0550bf113e..b6e6642f11 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -125,6 +125,7 @@ module Rails def test empty_directory_with_keep_file 'test/fixtures' + empty_directory_with_keep_file 'test/fixtures/files' empty_directory_with_keep_file 'test/controllers' empty_directory_with_keep_file 'test/mailers' empty_directory_with_keep_file 'test/models' @@ -234,7 +235,7 @@ module Rails end def create_test_files - build(:test) unless options[:skip_test_unit] + build(:test) unless options[:skip_test] end def create_tmp_files diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 20ee229e97..a2661bfb51 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -12,7 +12,7 @@ require "action_controller/railtie" <%= comment_if :skip_action_mailer %>require "action_mailer/railtie" require "action_view/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" -<%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" +<%= comment_if :skip_test %>require "rails/test_unit/railtie" <% end -%> # Require the gems listed in Gemfile, including any gems diff --git a/railties/lib/rails/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE index b8f7845896..11daa5c3cb 100644 --- a/railties/lib/rails/generators/rails/model/USAGE +++ b/railties/lib/rails/generators/rails/model/USAGE @@ -22,7 +22,7 @@ Description: If you pass a namespaced model name (e.g. admin/account or Admin::Account) then the generator will create a module with a table_name_prefix method - to prefix the model's table name with the module name (e.g. admin_account) + to prefix the model's table name with the module name (e.g. admin_accounts) Available field types: diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index 1c270dd7d4..ab050fc246 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -18,14 +18,14 @@ module Rails def app if mountable? directory 'app' - empty_directory_with_keep_file "app/assets/images/#{name}" + empty_directory_with_keep_file "app/assets/images/#{namespaced_name}" elsif full? empty_directory_with_keep_file 'app/models' empty_directory_with_keep_file 'app/controllers' empty_directory_with_keep_file 'app/views' empty_directory_with_keep_file 'app/helpers' empty_directory_with_keep_file 'app/mailers' - empty_directory_with_keep_file "app/assets/images/#{name}" + empty_directory_with_keep_file "app/assets/images/#{namespaced_name}" end end @@ -50,10 +50,10 @@ module Rails end def lib - template "lib/%name%.rb" - template "lib/tasks/%name%_tasks.rake" - template "lib/%name%/version.rb" - template "lib/%name%/engine.rb" if engine? + template "lib/%namespaced_name%.rb" + template "lib/tasks/%namespaced_name%_tasks.rake" + template "lib/%namespaced_name%/version.rb" + template "lib/%namespaced_name%/engine.rb" if engine? end def config @@ -62,7 +62,7 @@ module Rails def test template "test/test_helper.rb" - template "test/%name%_test.rb" + template "test/%namespaced_name%_test.rb" append_file "Rakefile", <<-EOF #{rakefile_test_tasks} @@ -117,9 +117,9 @@ task default: :test def stylesheets if mountable? copy_file "rails/stylesheets.css", - "app/assets/stylesheets/#{name}/application.css" + "app/assets/stylesheets/#{namespaced_name}/application.css" elsif full? - empty_directory_with_keep_file "app/assets/stylesheets/#{name}" + empty_directory_with_keep_file "app/assets/stylesheets/#{namespaced_name}" end end @@ -128,9 +128,9 @@ task default: :test if mountable? template "rails/javascripts.js", - "app/assets/javascripts/#{name}/application.js" + "app/assets/javascripts/#{namespaced_name}/application.js" elsif full? - empty_directory_with_keep_file "app/assets/javascripts/#{name}" + empty_directory_with_keep_file "app/assets/javascripts/#{namespaced_name}" end end @@ -226,7 +226,7 @@ task default: :test end def create_test_files - build(:test) unless options[:skip_test_unit] + build(:test) unless options[:skip_test] end def create_test_dummy_files @@ -256,6 +256,14 @@ task default: :test end end + def underscored_name + @underscored_name ||= original_name.underscore + end + + def namespaced_name + @namespaced_name ||= name.gsub('-', '/') + end + protected def app_templates_dir @@ -294,7 +302,7 @@ task default: :test end def with_dummy_app? - options[:skip_test_unit].blank? || options[:dummy_path] != 'test/dummy' + options[:skip_test].blank? || options[:dummy_path] != 'test/dummy' end def self.banner @@ -305,6 +313,27 @@ task default: :test @original_name ||= File.basename(destination_root) end + def modules + @modules ||= namespaced_name.camelize.split("::") + end + + def wrap_in_modules(content) + content = "#{content}".strip.gsub(/\W$\n/, '') + modules.reverse.inject(content) do |content, mod| + str = "module #{mod}\n" + str += content.lines.map { |line| " #{line}" }.join + str += content.present? ? "\nend" : "end" + end + end + + def camelized_modules + @camelized_modules ||= namespaced_name.camelize + end + + def humanized + @humanized ||= original_name.underscore.humanize + end + def camelized @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize end @@ -328,8 +357,10 @@ task default: :test end def valid_const? - if original_name =~ /[^0-9a-zA-Z_]+/ - raise Error, "Invalid plugin name #{original_name}. Please give a name which use only alphabetic or numeric or \"_\" characters." + if original_name =~ /-\d/ + raise Error, "Invalid plugin name #{original_name}. Please give a name which does not contain a namespace starting with numeric characters." + elsif original_name =~ /[^\w-]+/ + raise Error, "Invalid plugin name #{original_name}. Please give a name which uses only alphabetic, numeric, \"_\" or \"-\" characters." elsif camelized =~ /^\d/ raise Error, "Invalid plugin name #{original_name}. Please give a name which does not start with numbers." elsif RESERVED_NAMES.include?(name) diff --git a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec index 919c349470..f8ece4fe73 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec @@ -1,21 +1,21 @@ $:.push File.expand_path("../lib", __FILE__) # Maintain your gem's version: -require "<%= name %>/version" +require "<%= namespaced_name %>/version" # Describe your gem and declare its dependencies: Gem::Specification.new do |s| s.name = "<%= name %>" - s.version = <%= camelized %>::VERSION + s.version = <%= camelized_modules %>::VERSION s.authors = ["<%= author %>"] s.email = ["<%= email %>"] s.homepage = "TODO" - s.summary = "TODO: Summary of <%= camelized %>." - s.description = "TODO: Description of <%= camelized %>." + s.summary = "TODO: Summary of <%= camelized_modules %>." + s.description = "TODO: Description of <%= camelized_modules %>." s.license = "MIT" s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"] -<% unless options.skip_test_unit? -%> +<% unless options.skip_test? -%> s.test_files = Dir["test/**/*"] <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/README.rdoc b/railties/lib/rails/generators/rails/plugin/templates/README.rdoc index 301d647731..25983ca5da 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/README.rdoc +++ b/railties/lib/rails/generators/rails/plugin/templates/README.rdoc @@ -1,3 +1,3 @@ -= <%= camelized %> += <%= camelized_modules %> This project rocks and uses MIT-LICENSE.
\ No newline at end of file diff --git a/railties/lib/rails/generators/rails/plugin/templates/Rakefile b/railties/lib/rails/generators/rails/plugin/templates/Rakefile index c338a0bdb1..bda55bae29 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile @@ -8,7 +8,7 @@ require 'rdoc/task' RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' - rdoc.title = '<%= camelized %>' + rdoc.title = '<%= camelized_modules %>' rdoc.options << '--line-numbers' rdoc.rdoc_files.include('README.rdoc') rdoc.rdoc_files.include('lib/**/*.rb') diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt index 448ad7f989..7157e48c42 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt @@ -1,4 +1,5 @@ -module <%= camelized %> +<%= wrap_in_modules <<-rb.strip_heredoc class ApplicationController < ActionController::Base end -end +rb +%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt deleted file mode 100644 index 40ae9f52c2..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt +++ /dev/null @@ -1,4 +0,0 @@ -module <%= camelized %> - module ApplicationHelper - end -end diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt new file mode 100644 index 0000000000..25d692732d --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt @@ -0,0 +1,5 @@ +<%= wrap_in_modules <<-rb.strip_heredoc + module ApplicationHelper + end +rb +%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt deleted file mode 100644 index 1d380420b4..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt +++ /dev/null @@ -1,14 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title><%= camelized %></title> - <%%= stylesheet_link_tag "<%= name %>/application", media: "all" %> - <%%= javascript_include_tag "<%= name %>/application" %> - <%%= csrf_meta_tags %> -</head> -<body> - -<%%= yield %> - -</body> -</html> diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt new file mode 100644 index 0000000000..6bc480161d --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<head> + <title><%= humanized %></title> + <%%= stylesheet_link_tag "<%= namespaced_name %>/application", media: "all" %> + <%%= javascript_include_tag "<%= namespaced_name %>/application" %> + <%%= csrf_meta_tags %> +</head> +<body> + +<%%= yield %> + +</body> +</html> diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt index c3314d7e68..3edaac35c9 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt @@ -1,7 +1,7 @@ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application. ENGINE_ROOT = File.expand_path('../..', __FILE__) -ENGINE_PATH = File.expand_path('../../lib/<%= name -%>/engine', __FILE__) +ENGINE_PATH = File.expand_path('../../lib/<%= namespaced_name -%>/engine', __FILE__) # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) diff --git a/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb index 8e158d5831..154452bfe5 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb @@ -1,5 +1,5 @@ <% if mountable? -%> -<%= camelized %>::Engine.routes.draw do +<%= camelized_modules %>::Engine.routes.draw do <% else -%> Rails.application.routes.draw do <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/gitignore b/railties/lib/rails/generators/rails/plugin/templates/gitignore index 086d87818a..d524fcbc4e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/gitignore +++ b/railties/lib/rails/generators/rails/plugin/templates/gitignore @@ -1,10 +1,10 @@ .bundle/ log/*.log pkg/ -<% unless options[:skip_test_unit] && options[:dummy_path] == 'test/dummy' -%> +<% unless options[:skip_test] && options[:dummy_path] == 'test/dummy' -%> <%= dummy_path %>/db/*.sqlite3 <%= dummy_path %>/db/*.sqlite3-journal <%= dummy_path %>/log/*.log <%= dummy_path %>/tmp/ <%= dummy_path %>/.sass-cache -<% end -%>
\ No newline at end of file +<% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb deleted file mode 100644 index 40c074cced..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb +++ /dev/null @@ -1,6 +0,0 @@ -<% if engine? -%> -require "<%= name %>/engine" - -<% end -%> -module <%= camelized %> -end diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb deleted file mode 100644 index 967668fe66..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb +++ /dev/null @@ -1,7 +0,0 @@ -module <%= camelized %> - class Engine < ::Rails::Engine -<% if mountable? -%> - isolate_namespace <%= camelized %> -<% end -%> - end -end diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb deleted file mode 100644 index ef07ef2e19..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module <%= camelized %> - VERSION = "0.0.1" -end diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb new file mode 100644 index 0000000000..40b1c4cee7 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb @@ -0,0 +1,5 @@ +<% if engine? -%> +require "<%= namespaced_name %>/engine" + +<% end -%> +<%= wrap_in_modules "# Your code goes here..." %> diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb new file mode 100644 index 0000000000..17afd52177 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb @@ -0,0 +1,6 @@ +<%= wrap_in_modules <<-rb.strip_heredoc + class Engine < ::Rails::Engine + #{mountable? ? ' isolate_namespace ' + camelized_modules : ' '} + end +rb +%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb new file mode 100644 index 0000000000..d257295988 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb @@ -0,0 +1 @@ +<%= wrap_in_modules 'VERSION = "0.0.1"' %> diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%name%_tasks.rake b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake index 7121f5ae23..88a2c4120f 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%name%_tasks.rake +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake @@ -1,4 +1,4 @@ # desc "Explaining what the task does" -# task :<%= name %> do +# task :<%= underscored_name %> do # # Task goes here # end diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb index 3a9a7e5437..b1038c839e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb @@ -9,10 +9,10 @@ require "action_controller/railtie" <%= comment_if :skip_action_mailer %>require "action_mailer/railtie" require "action_view/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" -<%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" +<%= comment_if :skip_test %>require "rails/test_unit/railtie" <% end -%> Bundler.require(*Rails.groups) -require "<%= name %>" +require "<%= namespaced_name %>" <%= application_definition %> diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb index 730ee31c3d..673de44108 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb @@ -1,4 +1,4 @@ Rails.application.routes.draw do - mount <%= camelized %>::Engine => "/<%= name %>" + mount <%= camelized_modules %>::Engine => "/<%= name %>" end diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb deleted file mode 100644 index 0a8bbd4aaf..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'test_helper' - -class <%= camelized %>Test < ActiveSupport::TestCase - test "truth" do - assert_kind_of Module, <%= camelized %> - end -end diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb new file mode 100644 index 0000000000..1ee05d7871 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class <%= camelized_modules %>::Test < ActiveSupport::TestCase + test "truth" do + assert_kind_of Module, <%= camelized_modules %> + end +end diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb index bf3da1fc4d..0852ffce9a 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb @@ -20,4 +20,6 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } # Load fixtures from the engine if ActiveSupport::TestCase.respond_to?(:fixture_path=) ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) + ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "files" + ActiveSupport::TestCase.fixtures :all end diff --git a/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css b/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css index 1ae7000299..69af1e8307 100644 --- a/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css +++ b/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css @@ -4,6 +4,7 @@ body, p, ol, ul, td { font-family: verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 18px; + margin: 33px; } pre { @@ -16,6 +17,16 @@ a { color: #000; } a:visited { color: #666; } a:hover { color: #fff; background-color:#000; } +th { + padding-bottom: 5px; +} + +td { + padding-bottom: 7px; + padding-left: 5px; + padding-right: 5px; +} + div.field, div.actions { margin-bottom: 10px; } diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index 18bd1ece9d..8d825ae7b0 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -19,30 +19,30 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase test "should create <%= singular_table_name %>" do assert_difference('<%= class_name %>.count') do - post :create, <%= "#{singular_table_name}: { #{attributes_hash} }" %> + post :create, params: { <%= "#{singular_table_name}: { #{attributes_hash} }" %> } end assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end test "should show <%= singular_table_name %>" do - get :show, id: <%= "@#{singular_table_name}" %> + get :show, params: { id: <%= "@#{singular_table_name}" %> } assert_response :success end test "should get edit" do - get :edit, id: <%= "@#{singular_table_name}" %> + get :edit, params: { id: <%= "@#{singular_table_name}" %> } assert_response :success end test "should update <%= singular_table_name %>" do - patch :update, id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %> + patch :update, params: { id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %> } assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end test "should destroy <%= singular_table_name %>" do assert_difference('<%= class_name %>.count', -1) do - delete :destroy, id: <%= "@#{singular_table_name}" %> + delete :destroy, params: { id: <%= "@#{singular_table_name}" %> } end assert_redirected_to <%= index_helper %>_path diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index c837fadb40..40a1915b54 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -21,6 +21,7 @@ if defined?(ActiveRecord::Base) class ActiveSupport::TestCase include ActiveRecord::TestFixtures self.fixture_path = "#{Rails.root}/test/fixtures/" + self.file_fixture_path = self.fixture_path + "files" end ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 032b11a95f..a12f3cfc24 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -47,9 +47,8 @@ module ApplicationTests def; end RUBY - error_stream = Tempfile.new('error') - redirect_stderr(error_stream) { run_test_command('test/models/error_test.rb') } - assert_match "syntax error", error_stream.read + error = capture(:stderr) { run_test_command('test/models/error_test.rb') } + assert_match "syntax error", error end def test_run_models @@ -296,15 +295,6 @@ module ApplicationTests app_file 'db/schema.rb', '' end - def redirect_stderr(target_stream) - previous_stderr = STDERR.dup - $stderr.reopen(target_stream) - yield - target_stream.rewind - ensure - $stderr = previous_stderr - end - def create_test_file(path = :unit, name = 'test') app_file "test/#{path}/#{name}_test.rb", <<-RUBY require 'test_helper' diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 5d270555ed..689173f184 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -33,6 +33,7 @@ DEFAULT_APP_FILES = %w( log test/test_helper.rb test/fixtures + test/fixtures/files test/controllers test/models test/helpers @@ -445,13 +446,13 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file 'lib/test_file.rb', 'heres test data' end - def test_test_unit_is_removed_from_frameworks_if_skip_test_unit_is_given - run_generator [destination_root, "--skip-test-unit"] + def test_tests_are_removed_from_frameworks_if_skip_test_is_given + run_generator [destination_root, "--skip-test"] assert_file "config/application.rb", /#\s+require\s+["']rails\/test_unit\/railtie["']/ end - def test_no_active_record_or_test_unit_if_skips_given - run_generator [destination_root, "--skip-test-unit", "--skip-active-record"] + def test_no_active_record_or_tests_if_skips_given + run_generator [destination_root, "--skip-test", "--skip-active-record"] assert_file "config/application.rb", /#\s+require\s+["']rails\/test_unit\/railtie["']/ assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/ assert_file "config/application.rb", /\s+require\s+["']active_job\/railtie["']/ diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 318ea5b2cb..9c49766a2f 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -28,11 +28,11 @@ class PluginGeneratorTest < Rails::Generators::TestCase include SharedGeneratorTests def test_invalid_plugin_name_raises_an_error - content = capture(:stderr){ run_generator [File.join(destination_root, "things-43")] } - assert_equal "Invalid plugin name things-43. Please give a name which use only alphabetic or numeric or \"_\" characters.\n", content + content = capture(:stderr){ run_generator [File.join(destination_root, "my_plugin-31fr-extension")] } + assert_equal "Invalid plugin name my_plugin-31fr-extension. Please give a name which does not contain a namespace starting with numeric characters.\n", content content = capture(:stderr){ run_generator [File.join(destination_root, "things4.3")] } - assert_equal "Invalid plugin name things4.3. Please give a name which use only alphabetic or numeric or \"_\" characters.\n", content + assert_equal "Invalid plugin name things4.3. Please give a name which uses only alphabetic, numeric, \"_\" or \"-\" characters.\n", content content = capture(:stderr){ run_generator [File.join(destination_root, "43things")] } assert_equal "Invalid plugin name 43things. Please give a name which does not start with numbers.\n", content @@ -44,7 +44,14 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_equal "Invalid plugin name Digest, constant Digest is already in use. Please choose another plugin name.\n", content end - def test_camelcase_plugin_name_underscores_filenames + def test_correct_file_in_lib_folder_of_hyphenated_plugin_name + run_generator [File.join(destination_root, "hyphenated-name")] + assert_no_file "hyphenated-name/lib/hyphenated-name.rb" + assert_no_file "hyphenated-name/lib/hyphenated_name.rb" + assert_file "hyphenated-name/lib/hyphenated/name.rb", /module Hyphenated\n module Name\n # Your code goes here...\n end\nend/ + end + + def test_correct_file_in_lib_folder_of_camelcase_plugin_name run_generator [File.join(destination_root, "CamelCasedName")] assert_no_file "CamelCasedName/lib/CamelCasedName.rb" assert_file "CamelCasedName/lib/camel_cased_name.rb", /module CamelCasedName/ @@ -112,7 +119,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase def test_ensure_that_test_dummy_can_be_generated_from_a_template FileUtils.cd(Rails.root) - run_generator([destination_root, "-m", "lib/create_test_dummy_template.rb", "--skip-test-unit"]) + run_generator([destination_root, "-m", "lib/create_test_dummy_template.rb", "--skip-test"]) assert_file "spec/dummy" assert_no_file "test" end @@ -252,6 +259,40 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "lib/bukkits.rb", /require "bukkits\/engine"/ end + def test_creating_engine_with_hyphenated_name_in_full_mode + run_generator [File.join(destination_root, "hyphenated-name"), "--full"] + assert_file "hyphenated-name/app/assets/javascripts/hyphenated/name" + assert_file "hyphenated-name/app/assets/stylesheets/hyphenated/name" + assert_file "hyphenated-name/app/assets/images/hyphenated/name" + assert_file "hyphenated-name/app/models" + assert_file "hyphenated-name/app/controllers" + assert_file "hyphenated-name/app/views" + assert_file "hyphenated-name/app/helpers" + assert_file "hyphenated-name/app/mailers" + assert_file "hyphenated-name/bin/rails" + assert_file "hyphenated-name/config/routes.rb", /Rails.application.routes.draw do/ + assert_file "hyphenated-name/lib/hyphenated/name/engine.rb", /module Hyphenated\n module Name\n class Engine < ::Rails::Engine\n end\n end\nend/ + assert_file "hyphenated-name/lib/hyphenated/name.rb", /require "hyphenated\/name\/engine"/ + assert_file "hyphenated-name/bin/rails", /\.\.\/\.\.\/lib\/hyphenated\/name\/engine/ + end + + def test_creating_engine_with_hyphenated_and_underscored_name_in_full_mode + run_generator [File.join(destination_root, "my_hyphenated-name"), "--full"] + assert_file "my_hyphenated-name/app/assets/javascripts/my_hyphenated/name" + assert_file "my_hyphenated-name/app/assets/stylesheets/my_hyphenated/name" + assert_file "my_hyphenated-name/app/assets/images/my_hyphenated/name" + assert_file "my_hyphenated-name/app/models" + assert_file "my_hyphenated-name/app/controllers" + assert_file "my_hyphenated-name/app/views" + assert_file "my_hyphenated-name/app/helpers" + assert_file "my_hyphenated-name/app/mailers" + assert_file "my_hyphenated-name/bin/rails" + assert_file "my_hyphenated-name/config/routes.rb", /Rails.application.routes.draw do/ + assert_file "my_hyphenated-name/lib/my_hyphenated/name/engine.rb", /module MyHyphenated\n module Name\n class Engine < ::Rails::Engine\n end\n end\nend/ + assert_file "my_hyphenated-name/lib/my_hyphenated/name.rb", /require "my_hyphenated\/name\/engine"/ + assert_file "my_hyphenated-name/bin/rails", /\.\.\/\.\.\/lib\/my_hyphenated\/name\/engine/ + end + def test_being_quiet_while_creating_dummy_application assert_no_match(/create\s+config\/application.rb/, run_generator) end @@ -277,6 +318,63 @@ class PluginGeneratorTest < Rails::Generators::TestCase end end + def test_create_mountable_application_with_mountable_option_and_hypenated_name + run_generator [File.join(destination_root, "hyphenated-name"), "--mountable"] + assert_file "hyphenated-name/app/assets/javascripts/hyphenated/name" + assert_file "hyphenated-name/app/assets/stylesheets/hyphenated/name" + assert_file "hyphenated-name/app/assets/images/hyphenated/name" + assert_file "hyphenated-name/config/routes.rb", /Hyphenated::Name::Engine.routes.draw do/ + assert_file "hyphenated-name/lib/hyphenated/name/version.rb", /module Hyphenated\n module Name\n VERSION = "0.0.1"\n end\nend/ + assert_file "hyphenated-name/lib/hyphenated/name/engine.rb", /module Hyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace Hyphenated::Name\n end\n end\nend/ + assert_file "hyphenated-name/lib/hyphenated/name.rb", /require "hyphenated\/name\/engine"/ + assert_file "hyphenated-name/test/dummy/config/routes.rb", /mount Hyphenated::Name::Engine => "\/hyphenated-name"/ + assert_file "hyphenated-name/app/controllers/hyphenated/name/application_controller.rb", /module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n end\n end\nend/ + assert_file "hyphenated-name/app/helpers/hyphenated/name/application_helper.rb", /module Hyphenated\n module Name\n module ApplicationHelper\n end\n end\nend/ + assert_file "hyphenated-name/app/views/layouts/hyphenated/name/application.html.erb" do |contents| + assert_match "<title>Hyphenated name</title>", contents + assert_match(/stylesheet_link_tag\s+['"]hyphenated\/name\/application['"]/, contents) + assert_match(/javascript_include_tag\s+['"]hyphenated\/name\/application['"]/, contents) + end + end + + def test_create_mountable_application_with_mountable_option_and_hypenated_and_underscored_name + run_generator [File.join(destination_root, "my_hyphenated-name"), "--mountable"] + assert_file "my_hyphenated-name/app/assets/javascripts/my_hyphenated/name" + assert_file "my_hyphenated-name/app/assets/stylesheets/my_hyphenated/name" + assert_file "my_hyphenated-name/app/assets/images/my_hyphenated/name" + assert_file "my_hyphenated-name/config/routes.rb", /MyHyphenated::Name::Engine.routes.draw do/ + assert_file "my_hyphenated-name/lib/my_hyphenated/name/version.rb", /module MyHyphenated\n module Name\n VERSION = "0.0.1"\n end\nend/ + assert_file "my_hyphenated-name/lib/my_hyphenated/name/engine.rb", /module MyHyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace MyHyphenated::Name\n end\n end\nend/ + assert_file "my_hyphenated-name/lib/my_hyphenated/name.rb", /require "my_hyphenated\/name\/engine"/ + assert_file "my_hyphenated-name/test/dummy/config/routes.rb", /mount MyHyphenated::Name::Engine => "\/my_hyphenated-name"/ + assert_file "my_hyphenated-name/app/controllers/my_hyphenated/name/application_controller.rb", /module MyHyphenated\n module Name\n class ApplicationController < ActionController::Base\n end\n end\nend/ + assert_file "my_hyphenated-name/app/helpers/my_hyphenated/name/application_helper.rb", /module MyHyphenated\n module Name\n module ApplicationHelper\n end\n end\nend/ + assert_file "my_hyphenated-name/app/views/layouts/my_hyphenated/name/application.html.erb" do |contents| + assert_match "<title>My hyphenated name</title>", contents + assert_match(/stylesheet_link_tag\s+['"]my_hyphenated\/name\/application['"]/, contents) + assert_match(/javascript_include_tag\s+['"]my_hyphenated\/name\/application['"]/, contents) + end + end + + def test_create_mountable_application_with_mountable_option_and_multiple_hypenates_in_name + run_generator [File.join(destination_root, "deep-hyphenated-name"), "--mountable"] + assert_file "deep-hyphenated-name/app/assets/javascripts/deep/hyphenated/name" + assert_file "deep-hyphenated-name/app/assets/stylesheets/deep/hyphenated/name" + assert_file "deep-hyphenated-name/app/assets/images/deep/hyphenated/name" + assert_file "deep-hyphenated-name/config/routes.rb", /Deep::Hyphenated::Name::Engine.routes.draw do/ + assert_file "deep-hyphenated-name/lib/deep/hyphenated/name/version.rb", /module Deep\n module Hyphenated\n module Name\n VERSION = "0.0.1"\n end\n end\nend/ + assert_file "deep-hyphenated-name/lib/deep/hyphenated/name/engine.rb", /module Deep\n module Hyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace Deep::Hyphenated::Name\n end\n end\n end\nend/ + assert_file "deep-hyphenated-name/lib/deep/hyphenated/name.rb", /require "deep\/hyphenated\/name\/engine"/ + assert_file "deep-hyphenated-name/test/dummy/config/routes.rb", /mount Deep::Hyphenated::Name::Engine => "\/deep-hyphenated-name"/ + assert_file "deep-hyphenated-name/app/controllers/deep/hyphenated/name/application_controller.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n end\n end\n end\nend/ + assert_file "deep-hyphenated-name/app/helpers/deep/hyphenated/name/application_helper.rb", /module Deep\n module Hyphenated\n module Name\n module ApplicationHelper\n end\n end\n end\nend/ + assert_file "deep-hyphenated-name/app/views/layouts/deep/hyphenated/name/application.html.erb" do |contents| + assert_match "<title>Deep hyphenated name</title>", contents + assert_match(/stylesheet_link_tag\s+['"]deep\/hyphenated\/name\/application['"]/, contents) + assert_match(/javascript_include_tag\s+['"]deep\/hyphenated\/name\/application['"]/, contents) + end + end + def test_creating_gemspec run_generator assert_file "bukkits.gemspec", /s.name\s+= "bukkits"/ @@ -321,7 +419,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_creating_dummy_without_tests_but_with_dummy_path - run_generator [destination_root, "--dummy_path", "spec/dummy", "--skip-test-unit"] + run_generator [destination_root, "--dummy_path", "spec/dummy", "--skip-test"] assert_file "spec/dummy" assert_file "spec/dummy/config/application.rb" assert_no_file "test" @@ -333,14 +431,14 @@ class PluginGeneratorTest < Rails::Generators::TestCase def test_ensure_that_gitignore_can_be_generated_from_a_template_for_dummy_path FileUtils.cd(Rails.root) - run_generator([destination_root, "--dummy_path", "spec/dummy", "--skip-test-unit"]) + run_generator([destination_root, "--dummy_path", "spec/dummy", "--skip-test"]) assert_file ".gitignore" do |contents| assert_match(/spec\/dummy/, contents) end end - def test_skipping_test_unit - run_generator [destination_root, "--skip-test-unit"] + def test_skipping_test_files + run_generator [destination_root, "--skip-test"] assert_no_file "test" assert_file "bukkits.gemspec" do |contents| assert_no_match(/s.test_files = Dir\["test\/\*\*\/\*"\]/, contents) diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index ca972a3bdd..34e752cea1 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -106,8 +106,8 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase assert_file "test/controllers/users_controller_test.rb" do |content| assert_match(/class UsersControllerTest < ActionController::TestCase/, content) assert_match(/test "should get index"/, content) - assert_match(/post :create, user: \{ age: @user\.age, name: @user\.name, organization_id: @user\.organization_id, organization_type: @user\.organization_type \}/, content) - assert_match(/patch :update, id: @user, user: \{ age: @user\.age, name: @user\.name, organization_id: @user\.organization_id, organization_type: @user\.organization_type \}/, content) + assert_match(/post :create, params: \{ user: \{ age: @user\.age, name: @user\.name, organization_id: @user\.organization_id, organization_type: @user\.organization_type \} \}/, content) + assert_match(/patch :update, params: \{ id: @user, user: \{ age: @user\.age, name: @user\.name, organization_id: @user\.organization_id, organization_type: @user\.organization_type \} \}/, content) end end @@ -117,8 +117,8 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase assert_file "test/controllers/users_controller_test.rb" do |content| assert_match(/class UsersControllerTest < ActionController::TestCase/, content) assert_match(/test "should get index"/, content) - assert_match(/post :create, user: \{ \}/, content) - assert_match(/patch :update, id: @user, user: \{ \}/, content) + assert_match(/post :create, params: \{ user: \{ \} \}/, content) + assert_match(/patch :update, params: \{ id: @user, user: \{ \} \}/, content) end end diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 3b545328b5..2ec749373b 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -58,8 +58,8 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_file "test/controllers/product_lines_controller_test.rb" do |test| assert_match(/class ProductLinesControllerTest < ActionController::TestCase/, test) - assert_match(/post :create, product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \}/, test) - assert_match(/patch :update, id: @product_line, product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \}/, test) + assert_match(/post :create, params: \{ product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \} \}/, test) + assert_match(/patch :update, params: \{ id: @product_line, product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \} \}/, test) end # Views @@ -93,8 +93,8 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_file "test/controllers/product_lines_controller_test.rb" do |content| assert_match(/class ProductLinesControllerTest < ActionController::TestCase/, content) assert_match(/test "should get index"/, content) - assert_match(/post :create, product_line: \{ \}/, content) - assert_match(/patch :update, id: @product_line, product_line: \{ \}/, content) + assert_match(/post :create, params: \{ product_line: \{ \} \}/, content) + assert_match(/patch :update, params: \{ id: @product_line, product_line: \{ \} \}/, content) end end diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index b998fef42e..68f07f29d7 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -47,8 +47,8 @@ module SharedGeneratorTests assert_match(/Invalid value for \-\-database option/, content) end - def test_test_unit_is_skipped_if_required - run_generator [destination_root, "--skip-test-unit"] + def test_test_files_are_skipped_if_required + run_generator [destination_root, "--skip-test"] assert_no_file "test" end |