aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--RELEASING_RAILS.md (renamed from RELEASING_RAILS.rdoc)84
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb4
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb28
-rw-r--r--actionpack/lib/action_dispatch/journey/routes.rb9
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb13
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb20
-rw-r--r--actionpack/test/journey/router_test.rb289
-rw-r--r--actionpack/test/journey/routes_test.rb45
-rw-r--r--actionview/CHANGELOG.md5
-rw-r--r--actionview/lib/action_view/base.rb4
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/date_helper.rb1
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb32
-rw-r--r--actionview/lib/action_view/helpers/sanitize_helper.rb2
-rw-r--r--actionview/test/template/form_helper_test.rb18
-rw-r--r--actionview/test/template/form_tag_helper_test.rb40
-rw-r--r--actionview/test/template/test_case_test.rb2
-rw-r--r--activejob/lib/active_job/test_helper.rb6
-rw-r--r--activejob/test/support/integration/adapters/sidekiq.rb2
-rw-r--r--guides/source/configuring.md3
-rw-r--r--guides/source/testing.md634
-rw-r--r--railties/CHANGELOG.md11
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt3
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb2
-rw-r--r--railties/lib/rails/paths.rb6
-rw-r--r--railties/test/generators/plugin_generator_test.rb6
27 files changed, 616 insertions, 659 deletions
diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.md
index a020b958e1..faf8fa7f0d 100644
--- a/RELEASING_RAILS.rdoc
+++ b/RELEASING_RAILS.md
@@ -1,43 +1,47 @@
-= Releasing Rails
+# Releasing Rails
In this document, we'll cover the steps necessary to release Rails. Each
section contains steps to take during that time before the release. The times
suggested in each header are just that: suggestions. However, they should
really be considered as minimums.
-== 10 Days before release
+## 10 Days before release
Today is mostly coordination tasks. Here are the things you must do today:
-=== Is the CI green? If not, make it green. (See "Fixing the CI")
+### Is the CI green? If not, make it green. (See "Fixing the CI")
Do not release with a Red CI. You can find the CI status here:
- http://travis-ci.org/rails/rails
+```
+http://travis-ci.org/rails/rails
+```
-=== Is Sam Ruby happy? If not, make him happy.
+### Is Sam Ruby happy? If not, make him happy.
Sam Ruby keeps a test suite that makes sure the code samples in his book (Agile
Web Development with Rails) all work. These are valuable integration tests
for Rails. You can check the status of his tests here:
- http://intertwingly.net/projects/dashboard.html
+```
+http://intertwingly.net/projects/dashboard.html
+```
Do not release with Red AWDwR tests.
-=== Do we have any Git dependencies? If so, contact those authors.
+### Do we have any Git dependencies? If so, contact those authors.
Having Git dependencies indicates that we depend on unreleased code.
Obviously Rails cannot be released when it depends on unreleased code.
Contact the authors of those particular gems and work out a release date that
suits them.
-=== Contact the security team (either Koz or tenderlove)
+### Contact the security team (either Koz or tenderlove)
Let them know of your plans to release. There may be security issues to be
addressed, and that can impact your release date.
-=== Notify implementors.
+### Notify implementors.
Ruby implementors have high stakes in making sure Rails works. Be kind and
give them a heads up that Rails will be released soonish.
@@ -54,27 +58,29 @@ lists:
Implementors will love you and help you.
-== 3 Days before release
+### 3 Days before release
This is when you should release the release candidate. Here are your tasks
for today:
-=== Is the CI green? If not, make it green.
+### Is the CI green? If not, make it green.
-=== Is Sam Ruby happy? If not, make him happy.
+### Is Sam Ruby happy? If not, make him happy.
-=== Contact the security team. CVE emails must be sent on this day.
+### Contact the security team. CVE emails must be sent on this day.
-=== Create a release branch.
+### Create a release branch.
From the stable branch, create a release branch. For example, if you're
releasing Rails 3.0.10, do this:
- [aaron@higgins rails (3-0-stable)]$ git checkout -b 3-0-10
- Switched to a new branch '3-0-10'
- [aaron@higgins rails (3-0-10)]$
+```
+[aaron@higgins rails (3-0-stable)]$ git checkout -b 3-0-10
+Switched to a new branch '3-0-10'
+[aaron@higgins rails (3-0-10)]$
+```
-=== Update each CHANGELOG.
+### Update each CHANGELOG.
Many times commits are made without the CHANGELOG being updated. You should
review the commits since the last release, and fill in any missing information
@@ -82,15 +88,17 @@ for each CHANGELOG.
You can review the commits for the 3.0.10 release like this:
- [aaron@higgins rails (3-0-10)]$ git log v3.0.9..
+```
+[aaron@higgins rails (3-0-10)]$ git log v3.0.9..
+```
If you're doing a stable branch release, you should also ensure that all of
the CHANGELOG entries in the stable branch are also synced to the master
branch.
-=== Update the RAILS_VERSION file to include the RC.
+### Update the RAILS_VERSION file to include the RC.
-=== Build and test the gem.
+### Build and test the gem.
Run `rake install` to generate the gems and install them locally. Then try
generating a new app and ensure that nothing explodes.
@@ -98,7 +106,7 @@ generating a new app and ensure that nothing explodes.
This will stop you from looking silly when you push an RC to rubygems.org and
then realize it is broken.
-=== Release the gem.
+### Release the gem.
IMPORTANT: Due to YAML parse problems on the rubygems.org server, it is safest
to use Ruby 1.8 when releasing.
@@ -108,14 +116,16 @@ RAILS_VERSION, commit the changes, tag it, and push the gems to rubygems.org.
Here are the commands that `rake release` should use, so you can understand
what to do in case anything goes wrong:
- $ rake all:build
- $ git commit -am'updating RAILS_VERSION'
- $ git tag -m 'v3.0.10.rc1 release' v3.0.10.rc1
- $ git push
- $ git push --tags
- $ for i in $(ls pkg); do gem push $i; done
+```
+$ rake all:build
+$ git commit -am'updating RAILS_VERSION'
+$ git tag -m 'v3.0.10.rc1 release' v3.0.10.rc1
+$ git push
+$ git push --tags
+$ for i in $(ls pkg); do gem push $i; done
+```
-=== Send Rails release announcements
+### Send Rails release announcements
Write a release announcement that includes the version, changes, and links to
GitHub where people can find the specific commit list. Here are the mailing
@@ -132,16 +142,16 @@ IMPORTANT: If any users experience regressions when using the release
candidate, you *must* postpone the release. Bugfix releases *should not*
break existing applications.
-=== Post the announcement to the Rails blog.
+### Post the announcement to the Rails blog.
If you used Markdown format for your email, you can just paste it in to the
blog.
* http://weblog.rubyonrails.org
-=== Post the announcement to the Rails Twitter account.
+### Post the announcement to the Rails Twitter account.
-== Time between release candidate and actual release
+## Time between release candidate and actual release
Check the rails-core mailing list and the GitHub issue list for regressions in
the RC.
@@ -155,7 +165,7 @@ When you fix the regressions, do not create a new branch. Fix them on the
stable branch, then cherry pick the commit to your release branch. No other
commits should be added to the release branch besides regression fixing commits.
-== Day of release
+## Day of release
Many of these steps are the same as for the release candidate, so if you need
more explanation on a particular step, see the RC steps.
@@ -173,7 +183,7 @@ Today, do this stuff in this order:
* Email security lists
* Email general announcement lists
-=== Emailing the Rails security announce list
+### Emailing the Rails security announce list
Email the security announce list once for each vulnerability fixed.
@@ -193,13 +203,13 @@ so we need to give them the security fixes in patch form.
* Merge the release branch to the stable branch.
* Drink beer (or other cocktail)
-== Misc
+## Misc
-=== Fixing the CI
+### Fixing the CI
There are two simple steps for fixing the CI:
1. Identify the problem
2. Fix it
-Repeat these steps until the CI is green.
+Repeat these steps until the CI is green. \ No newline at end of file
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 5514213ad8..887196b3d2 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -54,11 +54,11 @@ module AbstractController
Mime::TEXT
end
- DEFAULT_PROTECTED_INSTANCE_VARIABLES = Set.new %w(
+ DEFAULT_PROTECTED_INSTANCE_VARIABLES = Set.new %i(
@_action_name @_response_body @_formats @_prefixes @_config
@_view_context_class @_view_renderer @_lookup_context
@_routes @_db_runtime
- ).map(&:to_sym)
+ )
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index e78f1f0d7e..fc8e345d43 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -461,7 +461,7 @@ module ActionController
end
end
- # Performs keys transfomration and returns the altered
+ # Performs keys transformation and returns the altered
# <tt>ActionController::Parameters</tt> instance.
def transform_keys!(&block)
@parameters.transform_keys!(&block)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 39069f7378..94f18cefc3 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -42,14 +42,12 @@ module ActionController
@env["action_dispatch.request.request_parameters"] = params
end
- def assign_parameters(routes, controller_path, action, parameters = {})
- parameters = parameters.symbolize_keys
- generated_path, query_string_keys = routes.generate_extras(parameters.merge(:controller => controller_path, :action => action))
+ def assign_parameters(routes, controller_path, action, parameters, generated_path, query_string_keys)
non_path_parameters = {}
path_parameters = {}
parameters.each do |key, value|
- if query_string_keys.include?(key) || key == :action || key == :controller
+ if query_string_keys.include?(key)
non_path_parameters[key] = value
else
if value.is_a?(Array)
@@ -483,11 +481,13 @@ module ActionController
@request.env['REQUEST_METHOD'] = http_method
- controller_class_name = @controller.class.anonymous? ?
- "anonymous" :
- @controller.class.controller_path
+ parameters = parameters.symbolize_keys
- @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters)
+ generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action.to_s))
+ generated_path = generated_path(generated_extras)
+ query_string_keys = query_parameter_names(generated_extras)
+
+ @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters, generated_path, query_string_keys)
@request.session.update(session) if session
@request.flash.update(flash || {})
@@ -530,6 +530,18 @@ module ActionController
@response
end
+ def controller_class_name
+ @controller.class.anonymous? ? "anonymous" : @controller.class.controller_path
+ end
+
+ def generated_path(generated_extras)
+ generated_extras[0]
+ end
+
+ def query_parameter_names(generated_extras)
+ generated_extras[1] + [:controller, :action]
+ end
+
def setup_controller_request_and_response
@controller = nil unless defined? @controller
diff --git a/actionpack/lib/action_dispatch/journey/routes.rb b/actionpack/lib/action_dispatch/journey/routes.rb
index 4770b8b7cc..f7b009109e 100644
--- a/actionpack/lib/action_dispatch/journey/routes.rb
+++ b/actionpack/lib/action_dispatch/journey/routes.rb
@@ -61,14 +61,7 @@ module ActionDispatch
end
def add_route(name, mapping)
- route = Route.new(name,
- mapping.application,
- mapping.path,
- mapping.conditions,
- mapping.required_defaults,
- mapping.defaults)
-
- route.precedence = routes.length
+ route = mapping.make_route name, routes.length
routes << route
partition_route(route)
clear_cache!
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index e65279a285..402ad778fa 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,9 +1,14 @@
-require 'active_support/core_ext/hash/conversions'
require 'action_dispatch/http/request'
-require 'active_support/core_ext/hash/indifferent_access'
module ActionDispatch
+ # ActionDispatch::ParamsParser works for all the requests having any Content-Length
+ # (like POST). It takes raw data from the request and puts it through the parser
+ # that is picked based on Content-Type header.
+ #
+ # In case of any error while parsing data ParamsParser::ParseError is raised.
class ParamsParser
+ # Raised when raw data from the request cannot be parsed by the parser
+ # defined for request's content mime type.
class ParseError < StandardError
attr_reader :original_exception
@@ -21,6 +26,10 @@ module ActionDispatch
}
}
+ # Create a new +ParamsParser+ middleware instance.
+ #
+ # The +parsers+ argument can take Hash of parsers where key is identifying
+ # content mime type, and value is a lambda that is going to process data.
def initialize(app, parsers = {})
@app, @parsers = app, DEFAULT_PARSERS.merge(parsers)
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index d80faf7423..a9dae77e51 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -109,6 +109,7 @@ module ActionDispatch
@default_action = default_action
@ast = ast
@anchor = anchor
+ @via = via
path_params = ast.find_all(&:symbol?).map(&:to_sym)
@@ -140,9 +141,18 @@ module ActionDispatch
@defaults = formats[:defaults].merge(@defaults).merge(normalize_defaults(options))
@required_defaults = (split_options[:required_defaults] || []).map(&:first)
- unless via == [:all]
- @conditions[:request_method] = via.map { |m| m.to_s.dasherize.upcase }
- end
+ end
+
+ def make_route(name, precedence)
+ route = Journey::Route.new(name,
+ application,
+ path,
+ conditions,
+ required_defaults,
+ defaults)
+
+ route.precedence = precedence
+ route
end
def application
@@ -164,8 +174,8 @@ module ActionDispatch
# :request_method represents the HTTP verb that matches this route.
#
# Here we munge values before they get sent on to rack-mount.
- verbs = conditions[:request_method] || []
- unless verbs.empty?
+ unless @via == [:all]
+ verbs = @via.map { |m| m.to_s.dasherize.upcase }
conditions[:request_method] = %r[^#{verbs.join('|')}$]
end
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index 8a1414de8e..d512dae4e7 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -4,7 +4,7 @@ require 'abstract_unit'
module ActionDispatch
module Journey
class TestRouter < ActiveSupport::TestCase
- attr_reader :routes
+ attr_reader :routes, :mapper
def setup
@app = Routing::RouteSet::Dispatcher.new({})
@@ -12,125 +12,35 @@ module ActionDispatch
@routes = @route_set.router.routes
@router = @route_set.router
@formatter = @route_set.formatter
- end
-
- class FakeRequestFeeler < ActionDispatch::Request
- attr_writer :env
- attr_accessor :called
-
- def new env
- self.env = env
- self
- end
-
- def hello
- self.called = true
- 'world'
- end
+ @mapper = ActionDispatch::Routing::Mapper.new @route_set
end
def test_dashes
- router = Router.new(routes)
-
- path = Path::Pattern.build '/foo-bar-baz', {}, ['/.?'], true
-
- add_route nil, path, {}, [], {:id => nil}, {}
+ mapper.get '/foo-bar-baz', to: 'foo#bar'
env = rails_env 'PATH_INFO' => '/foo-bar-baz'
called = false
- router.recognize(env) do |r, params|
+ @router.recognize(env) do |r, params|
called = true
end
assert called
end
def test_unicode
- router = Router.new(routes)
+ mapper.get '/ほげ', to: 'foo#bar'
#match the escaped version of /ほげ
- path = Path::Pattern.build '/%E3%81%BB%E3%81%92', {}, ['/.?'], true
-
- add_route nil, path, {}, [], {:id => nil}, {}
-
env = rails_env 'PATH_INFO' => '/%E3%81%BB%E3%81%92'
called = false
- router.recognize(env) do |r, params|
+ @router.recognize(env) do |r, params|
called = true
end
assert called
end
- def test_request_class_and_requirements_success
- klass = FakeRequestFeeler.new nil
- router = Router.new(routes)
-
- requirements = { :hello => /world/ }
-
- path = Path::Pattern.build '/foo(/:id)', {}, ['/.?'], true
-
- add_route nil, path, requirements, [], {:id => nil}, {}
-
- env = rails_env({'PATH_INFO' => '/foo/10'}, klass)
- router.recognize(env) do |r, params|
- assert_equal({:id => '10'}, params)
- end
-
- assert klass.called, 'hello should have been called'
- assert_equal env.env, klass.env
- end
-
- def test_request_class_and_requirements_fail
- klass = FakeRequestFeeler.new nil
- router = Router.new(routes)
-
- requirements = { :hello => /mom/ }
-
- path = Path::Pattern.build '/foo(/:id)', {}, ['/.?'], true
-
- add_route nil, path, requirements, [], {:id => nil}, {}
-
- env = rails_env({'PATH_INFO' => '/foo/10'}, klass)
- router.recognize(env) do |r, params|
- flunk 'route should not be found'
- end
-
- assert klass.called, 'hello should have been called'
- assert_equal env.env, klass.env
- end
-
- class CustomPathRequest < ActionDispatch::Request
- def path_info
- env['custom.path_info']
- end
-
- def path_info=(x)
- env['custom.path_info'] = x
- end
- end
-
- def test_request_class_overrides_path_info
- router = Router.new(routes)
-
- path = Path::Pattern.build '/bar', {}, ['/.?'], true
-
- add_route nil, path, {}, [], {}, {}
-
- env = rails_env({'PATH_INFO' => '/foo',
- 'custom.path_info' => '/bar'}, CustomPathRequest)
-
- recognized = false
- router.recognize(env) do |r, params|
- recognized = true
- end
-
- assert recognized, "route should have been recognized"
- end
-
def test_regexp_first_precedence
- add_routes @router, [
- Path::Pattern.build("/whois/:domain", {:domain => /\w+\.[\w\.]+/}, ['/', '.', '?'], true),
- Path::Pattern.build("/whois/:id(.:format)", {}, ['/', '.', '?'], true)
- ]
+ mapper.get "/whois/:domain", :domain => /\w+\.[\w\.]+/, to: "foo#bar"
+ mapper.get "/whois/:id(.:format)", to: "foo#baz"
env = rails_env 'PATH_INFO' => '/whois/example.com'
@@ -142,25 +52,21 @@ module ActionDispatch
r = list.first
- assert_equal '/whois/:domain', r.path.spec.to_s
+ assert_equal '/whois/:domain(.:format)', r.path.spec.to_s
end
def test_required_parts_verified_are_anchored
- add_routes @router, [
- Path::Pattern.build("/foo/:id", { :id => /\d/ }, ['/', '.', '?'], false)
- ]
+ mapper.get "/foo/:id", :id => /\d/, anchor: false, to: "foo#bar"
assert_raises(ActionController::UrlGenerationError) do
- @formatter.generate(nil, { :id => '10' }, { })
+ @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => '10' }, { })
end
end
def test_required_parts_are_verified_when_building
- add_routes @router, [
- Path::Pattern.build("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false)
- ]
+ mapper.get "/foo/:id", :id => /\d+/, anchor: false, to: "foo#bar"
- path, _ = @formatter.generate(nil, { :id => '10' }, { })
+ path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => '10' }, { })
assert_equal '/foo/10', path
assert_raises(ActionController::UrlGenerationError) do
@@ -169,17 +75,15 @@ module ActionDispatch
end
def test_only_required_parts_are_verified
- add_routes @router, [
- Path::Pattern.build("/foo(/:id)", {:id => /\d/}, ['/', '.', '?'], false)
- ]
+ mapper.get "/foo(/:id)", :id => /\d/, :to => "foo#bar"
- path, _ = @formatter.generate(nil, { :id => '10' }, { })
+ path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => '10' }, { })
assert_equal '/foo/10', path
- path, _ = @formatter.generate(nil, { }, { })
+ path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar" }, { })
assert_equal '/foo', path
- path, _ = @formatter.generate(nil, { :id => 'aa' }, { })
+ path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => 'aa' }, { })
assert_equal '/foo/aa', path
end
@@ -206,7 +110,7 @@ module ActionDispatch
end
def test_X_Cascade
- add_routes @router, [ "/messages(.:format)" ]
+ mapper.get "/messages(.:format)", to: "foo#bar"
resp = @router.serve(rails_env({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' }))
assert_equal ['Not Found'], resp.last
assert_equal 'pass', resp[1]['X-Cascade']
@@ -227,24 +131,21 @@ module ActionDispatch
end
def test_defaults_merge_correctly
- path = Path::Pattern.from_string '/foo(/:id)'
- add_route nil, path, {}, [], {:id => nil}, {}
+ mapper.get '/foo(/:id)', to: "foo#bar", id: nil
env = rails_env 'PATH_INFO' => '/foo/10'
@router.recognize(env) do |r, params|
- assert_equal({:id => '10'}, params)
+ assert_equal({:id => '10', :controller => "foo", :action => "bar"}, params)
end
env = rails_env 'PATH_INFO' => '/foo'
@router.recognize(env) do |r, params|
- assert_equal({:id => nil}, params)
+ assert_equal({:id => nil, :controller => "foo", :action => "bar"}, params)
end
end
def test_recognize_with_unbound_regexp
- add_routes @router, [
- Path::Pattern.build("/foo", { }, ['/', '.', '?'], false)
- ]
+ mapper.get "/foo", anchor: false, to: "foo#bar"
env = rails_env 'PATH_INFO' => '/foo/bar'
@@ -255,9 +156,7 @@ module ActionDispatch
end
def test_bound_regexp_keeps_path_info
- add_routes @router, [
- Path::Pattern.build("/foo", { }, ['/', '.', '?'], true)
- ]
+ mapper.get "/foo", to: "foo#bar"
env = rails_env 'PATH_INFO' => '/foo'
@@ -270,12 +169,14 @@ module ActionDispatch
end
def test_path_not_found
- add_routes @router, [
+ [
"/messages(.:format)",
"/messages/new(.:format)",
"/messages/:id/edit(.:format)",
"/messages/:id(.:format)"
- ]
+ ].each do |path|
+ mapper.get path, to: "foo#bar"
+ end
env = rails_env 'PATH_INFO' => '/messages/unknown/path'
yielded = false
@@ -286,32 +187,29 @@ module ActionDispatch
end
def test_required_part_in_recall
- add_routes @router, [ "/messages/:a/:b" ]
+ mapper.get "/messages/:a/:b", to: "foo#bar"
- path, _ = @formatter.generate(nil, { :a => 'a' }, { :b => 'b' })
+ path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :a => 'a' }, { :b => 'b' })
assert_equal "/messages/a/b", path
end
def test_splat_in_recall
- add_routes @router, [ "/*path" ]
+ mapper.get "/*path", to: "foo#bar"
- path, _ = @formatter.generate(nil, { }, { :path => 'b' })
+ path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar" }, { :path => 'b' })
assert_equal "/b", path
end
def test_recall_should_be_used_when_scoring
- add_routes @router, [
- "/messages/:action(/:id(.:format))",
- "/messages/:id(.:format)"
- ]
+ mapper.get "/messages/:action(/:id(.:format))", to: 'foo#bar'
+ mapper.get "/messages/:id(.:format)", to: 'bar#baz'
- path, _ = @formatter.generate(nil, { :id => 10 }, { :action => 'index' })
+ path, _ = @formatter.generate(nil, { :controller => "foo", :id => 10 }, { :action => 'index' })
assert_equal "/messages/index/10", path
end
def test_nil_path_parts_are_ignored
- path = Path::Pattern.from_string "/:controller(/:action(.:format))"
- add_route @app, path, {}, [], {}, {}
+ mapper.get "/:controller(/:action(.:format))", to: "tasks#lol"
params = { :controller => "tasks", :format => nil }
extras = { :action => 'lol' }
@@ -323,17 +221,14 @@ module ActionDispatch
def test_generate_slash
params = [ [:controller, "tasks"],
[:action, "show"] ]
- path = Path::Pattern.build("/", Hash[params], ['/', '.', '?'], true)
-
- add_route @app, path, {}, [], {}, {}
+ mapper.get "/", Hash[params]
path, _ = @formatter.generate(nil, Hash[params], {})
assert_equal '/', path
end
def test_generate_calls_param_proc
- path = Path::Pattern.from_string '/:controller(/:action)'
- add_route @app, path, {}, [], {}, {}
+ mapper.get '/:controller(/:action)', to: "foo#bar"
parameterized = []
params = [ [:controller, "tasks"],
@@ -349,8 +244,7 @@ module ActionDispatch
end
def test_generate_id
- path = Path::Pattern.from_string '/:controller(/:action)'
- add_route @app, path, {}, [], {}, {}
+ mapper.get '/:controller(/:action)', to: 'foo#bar'
path, params = @formatter.generate(
nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {})
@@ -359,8 +253,7 @@ module ActionDispatch
end
def test_generate_escapes
- path = Path::Pattern.from_string '/:controller(/:action)'
- add_route @app, path, {}, [], {}, {}
+ mapper.get '/:controller(/:action)', to: "foo#bar"
path, _ = @formatter.generate(nil,
{ :controller => "tasks",
@@ -370,8 +263,7 @@ module ActionDispatch
end
def test_generate_escapes_with_namespaced_controller
- path = Path::Pattern.from_string '/:controller(/:action)'
- add_route @app, path, {}, [], {}, {}
+ mapper.get '/:controller(/:action)', to: "foo#bar"
path, _ = @formatter.generate(
nil, { :controller => "admin/tasks",
@@ -381,8 +273,7 @@ module ActionDispatch
end
def test_generate_extra_params
- path = Path::Pattern.from_string '/:controller(/:action)'
- add_route @app, path, {}, [], {}, {}
+ mapper.get '/:controller(/:action)', to: "foo#bar"
path, params = @formatter.generate(
nil, { :id => 1,
@@ -395,8 +286,7 @@ module ActionDispatch
end
def test_generate_missing_keys_no_matches_different_format_keys
- path = Path::Pattern.from_string '/:controller/:action/:name'
- add_route @app, path, {}, [], {}, {}
+ mapper.get '/:controller/:action/:name', to: "foo#bar"
primarty_parameters = {
:id => 1,
:controller => "tasks",
@@ -422,8 +312,7 @@ module ActionDispatch
end
def test_generate_uses_recall_if_needed
- path = Path::Pattern.from_string '/:controller(/:action(/:id))'
- add_route @app, path, {}, [], {}, {}
+ mapper.get '/:controller(/:action(/:id))', to: "foo#bar"
path, params = @formatter.generate(
nil,
@@ -434,8 +323,7 @@ module ActionDispatch
end
def test_generate_with_name
- path = Path::Pattern.from_string '/:controller(/:action)'
- add_route @app, path, {}, [], {}, "tasks"
+ mapper.get '/:controller(/:action)', to: 'foo#bar', as: 'tasks'
path, params = @formatter.generate(
"tasks",
@@ -451,16 +339,15 @@ module ActionDispatch
'/content/show/10' => { :controller => 'content', :action => 'show', :id => "10" },
}.each do |request_path, expected|
define_method("test_recognize_#{expected.keys.map(&:to_s).join('_')}") do
- path = Path::Pattern.from_string "/:controller(/:action(/:id))"
- app = Object.new
- route = add_route(app, path, {}, [], {}, {})
+ mapper.get "/:controller(/:action(/:id))", to: 'foo#bar'
+ route = @routes.first
env = rails_env 'PATH_INFO' => request_path
called = false
@router.recognize(env) do |r, params|
assert_equal route, r
- assert_equal(expected, params)
+ assert_equal({ :action => "bar" }.merge(expected), params)
called = true
end
@@ -473,16 +360,15 @@ module ActionDispatch
:splat => ['/segment/a/b%20c+d', { :segment => 'segment', :splat => 'a/b c+d' }]
}.each do |name, (request_path, expected)|
define_method("test_recognize_#{name}") do
- path = Path::Pattern.from_string '/:segment/*splat'
- app = Object.new
- route = add_route(app, path, {}, [], {}, {})
+ mapper.get '/:segment/*splat', to: 'foo#bar'
env = rails_env 'PATH_INFO' => request_path
called = false
+ route = @routes.first
@router.recognize(env) do |r, params|
assert_equal route, r
- assert_equal(expected, params)
+ assert_equal(expected.merge(:controller=>"foo", :action=>"bar"), params)
called = true
end
@@ -491,14 +377,8 @@ module ActionDispatch
end
def test_namespaced_controller
- path = Path::Pattern.build(
- "/:controller(/:action(/:id))",
- { :controller => /.+?/ },
- ["/", ".", "?"],
- true
- )
- app = Object.new
- route = add_route(app, path, {}, [], {}, {})
+ mapper.get "/:controller(/:action(/:id))", { :controller => /.+?/ }
+ route = @routes.first
env = rails_env 'PATH_INFO' => '/admin/users/show/10'
called = false
@@ -517,9 +397,8 @@ module ActionDispatch
end
def test_recognize_literal
- path = Path::Pattern.from_string "/books(/:action(.:format))"
- app = Object.new
- route = add_route(app, path, {}, [], {:controller => 'books'})
+ mapper.get "/books(/:action(.:format))", controller: "books"
+ route = @routes.first
env = rails_env 'PATH_INFO' => '/books/list.rss'
expected = { :controller => 'books', :action => 'list', :format => 'rss' }
@@ -534,10 +413,7 @@ module ActionDispatch
end
def test_recognize_head_route
- path = Path::Pattern.from_string "/books(/:action(.:format))"
- app = Object.new
- conditions = { request_method: 'HEAD' }
- add_route(app, path, conditions, [], {})
+ mapper.match "/books(/:action(.:format))", via: 'head', to: 'foo#bar'
env = rails_env(
'PATH_INFO' => '/books/list.rss',
@@ -553,12 +429,7 @@ module ActionDispatch
end
def test_recognize_head_request_as_get_route
- path = Path::Pattern.from_string "/books(/:action(.:format))"
- app = Object.new
- conditions = {
- :request_method => 'GET'
- }
- add_route(app, path, conditions, [], {})
+ mapper.get "/books(/:action(.:format))", to: 'foo#bar'
env = rails_env 'PATH_INFO' => '/books/list.rss',
"REQUEST_METHOD" => "HEAD"
@@ -571,11 +442,8 @@ module ActionDispatch
assert called
end
- def test_recognize_cares_about_verbs
- path = Path::Pattern.from_string "/books(/:action(.:format))"
- app = Object.new
- conditions = { request_method: 'GET' }
- add_route(app, path, conditions, [], {})
+ def test_recognize_cares_about_get_verbs
+ mapper.match "/books(/:action(.:format))", to: "foo#bar", via: :get
env = rails_env 'PATH_INFO' => '/books/list.rss',
"REQUEST_METHOD" => "POST"
@@ -586,21 +454,48 @@ module ActionDispatch
end
assert_not called
+ end
- conditions = conditions.dup
- conditions[:request_method] = 'POST'
+ def test_recognize_cares_about_post_verbs
+ mapper.match "/books(/:action(.:format))", to: "foo#bar", via: :post
- post = add_route(app, path, conditions, [], {})
+ env = rails_env 'PATH_INFO' => '/books/list.rss',
+ "REQUEST_METHOD" => "POST"
called = false
@router.recognize(env) do |r, params|
- assert_equal post, r
called = true
end
assert called
end
+ def test_multi_verb_recognition
+ mapper.match "/books(/:action(.:format))", to: "foo#bar", via: [:post, :get]
+
+ %w( POST GET ).each do |verb|
+ env = rails_env 'PATH_INFO' => '/books/list.rss',
+ "REQUEST_METHOD" => verb
+
+ called = false
+ @router.recognize(env) do |r, params|
+ called = true
+ end
+
+ assert called
+ end
+
+ env = rails_env 'PATH_INFO' => '/books/list.rss',
+ "REQUEST_METHOD" => 'PUT'
+
+ called = false
+ @router.recognize(env) do |r, params|
+ called = true
+ end
+
+ assert_not called
+ end
+
private
def add_routes router, paths, anchor = true
@@ -637,12 +532,6 @@ module ActionDispatch
"CONTENT_LENGTH" => "0"
}.merge env
end
-
- MyMapping = Struct.new(:application, :path, :conditions, :required_defaults, :defaults)
-
- def add_route(app, path, conditions, required_defaults, defaults, name = nil)
- @routes.add_route(name, MyMapping.new(app, path, conditions, required_defaults, defaults))
- end
end
end
end
diff --git a/actionpack/test/journey/routes_test.rb b/actionpack/test/journey/routes_test.rb
index bbe3228bf2..f8293dfc5f 100644
--- a/actionpack/test/journey/routes_test.rb
+++ b/actionpack/test/journey/routes_test.rb
@@ -3,27 +3,19 @@ require 'abstract_unit'
module ActionDispatch
module Journey
class TestRoutes < ActiveSupport::TestCase
- attr_reader :routes
+ attr_reader :routes, :mapper
def setup
@route_set = ActionDispatch::Routing::RouteSet.new
@routes = @route_set.router.routes
@router = @route_set.router
+ @mapper = ActionDispatch::Routing::Mapper.new @route_set
super
end
- MyMapping = Struct.new(:application, :path, :conditions, :required_defaults, :defaults)
-
- def add_route(app, path, conditions, required_defaults, defaults, name = nil)
- @routes.add_route(name, MyMapping.new(app, path, conditions, required_defaults, defaults))
- end
-
def test_clear
- path = Path::Pattern.build '/foo(/:id)', {}, ['/.?'], true
- requirements = { :hello => /world/ }
-
- add_route nil, path, requirements, [], {:id => nil}, {}
- assert_not routes.empty?
+ mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron'
+ assert_not_predicate routes, :empty?
assert_equal 1, routes.length
routes.clear
@@ -32,41 +24,32 @@ module ActionDispatch
end
def test_ast
- path = Path::Pattern.from_string '/hello'
-
- add_route nil, path, {}, [], {}, {}
+ mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron'
ast = routes.ast
- add_route nil, path, {}, [], {}, {}
+ mapper.get "/foo(/:id)", to: "foo#bar", as: 'gorby'
assert_not_equal ast, routes.ast
end
def test_simulator_changes
- path = Path::Pattern.from_string '/hello'
-
- add_route nil, path, {}, [], {}, {}
+ mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron'
sim = routes.simulator
- add_route nil, path, {}, [], {}, {}
+ mapper.get "/foo(/:id)", to: "foo#bar", as: 'gorby'
assert_not_equal sim, routes.simulator
end
def test_partition_route
- path = Path::Pattern.from_string '/hello'
+ mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron'
- anchored_route = add_route nil, path, {}, [], {}, {}
- assert_equal [anchored_route], @routes.anchored_routes
- assert_equal [], @routes.custom_routes
+ assert_equal 1, @routes.anchored_routes.length
+ assert_predicate @routes.custom_routes, :empty?
- path = Path::Pattern.build(
- "/hello/:who", { who: /\d/ }, ['/', '.', '?'], false
- )
+ mapper.get "/hello/:who", to: "foo#bar", as: 'bar', who: /\d/
- custom_route = add_route nil, path, {}, [], {}, {}
- assert_equal [custom_route], @routes.custom_routes
- assert_equal [anchored_route], @routes.anchored_routes
+ assert_equal 1, @routes.custom_routes.length
+ assert_equal 1, @routes.anchored_routes.length
end
def test_first_name_wins
- mapper = ActionDispatch::Routing::Mapper.new @route_set
mapper.get "/hello", to: "foo#bar", as: 'aaron'
assert_raise(ArgumentError) do
mapper.get "/aaron", to: "foo#bar", as: 'aaron'
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index edc78118fb..90c9c2171c 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Make `disable_with` the default behavior for submit tags. Disables the
+ button on submit to prevent double submits.
+
+ *Justin Schiff*
+
* Add a break_sequence option to word_wrap so you can specify a custom break.
* Mauricio Gomez *
diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb
index 43124bb904..72ca6f7ec6 100644
--- a/actionview/lib/action_view/base.rb
+++ b/actionview/lib/action_view/base.rb
@@ -161,6 +161,10 @@ module ActionView #:nodoc:
cattr_accessor :raise_on_missing_translations
@@raise_on_missing_translations = false
+ # Specify whether submit_tag should automatically disable on click
+ cattr_accessor :automatically_disable_submit_tag
+ @@automatically_disable_submit_tag = true
+
class_attribute :_routes
class_attribute :logger
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index 6ac8185b0f..717b326740 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -48,10 +48,10 @@ module ActionView
# It is also possible the combination of additional connection overhead
# (DNS, SSL) and the overall browser connection limits may result in this
# solution being slower. You should be sure to measure your actual
- # performance across targeted browers both before and after this change.
+ # performance across targeted browsers both before and after this change.
#
# To implement the corresponding hosts you can either setup four actual
- # hosts or use wildcard DNS to CNAME the wilcard to a single asset host.
+ # hosts or use wildcard DNS to CNAME the wildcard to a single asset host.
# You can read more about setting up your DNS CNAME records from your ISP.
#
# Note: This is purely a browser performance optimization and is not meant
diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb
index 94fbaa2dca..312e41ee48 100644
--- a/actionview/lib/action_view/helpers/date_helper.rb
+++ b/actionview/lib/action_view/helpers/date_helper.rb
@@ -228,6 +228,7 @@ module ActionView
# or the given prompt string.
# * <tt>:with_css_classes</tt> - Set to true if you want assign different styles for 'select' tags. This option
# automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second' for your 'select' tags.
+ # * <tt>:use_hidden</tt> - Set to true if you only want to generate hidden input tags.
#
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
#
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index d36701955a..af684e05c6 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -414,34 +414,48 @@ module ActionView
# the form is processed normally, otherwise no action is taken.
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
# disabled version of the submit button when the form is submitted. This feature is
- # provided by the unobtrusive JavaScript driver.
+ # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
+ # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
#
# ==== Examples
# submit_tag
- # # => <input name="commit" type="submit" value="Save changes" />
+ # # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" />
#
# submit_tag "Edit this article"
- # # => <input name="commit" type="submit" value="Edit this article" />
+ # # => <input name="commit" data-disable-with="Edit this article" type="submit" value="Edit this article" />
#
# submit_tag "Save edits", disabled: true
- # # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
+ # # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" />
#
- # submit_tag "Complete sale", data: { disable_with: "Please wait..." }
- # # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" />
+ # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
+ # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
#
# submit_tag nil, class: "form_submit"
# # => <input class="form_submit" name="commit" type="submit" />
#
# submit_tag "Edit", class: "edit_button"
- # # => <input class="edit_button" name="commit" type="submit" value="Edit" />
+ # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
#
# submit_tag "Save", data: { confirm: "Are you sure?" }
- # # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
+ # # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
#
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
+ tag_options = { "type" => "submit", "name" => "commit", "value" => value }.update(options)
+
+ if ActionView::Base.automatically_disable_submit_tag
+ unless tag_options["data-disable-with"] == false || (tag_options["data"] && tag_options["data"][:disable_with] == false)
+ disable_with_text = tag_options["data-disable-with"]
+ disable_with_text ||= tag_options["data"][:disable_with] if tag_options["data"]
+ disable_with_text ||= value.clone
+ tag_options.deep_merge!("data" => { "disable_with" => disable_with_text })
+ else
+ tag_options.delete("data-disable-with")
+ tag_options["data"].delete(:disable_with) if tag_options["data"]
+ end
+ end
- tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options)
+ tag :input, tag_options
end
# Creates a button element that defines a <tt>submit</tt> button,
diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb
index a2e9f37453..191a881de0 100644
--- a/actionview/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionview/lib/action_view/helpers/sanitize_helper.rb
@@ -120,7 +120,7 @@ module ActionView
attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
# Vendors the full, link and white list sanitizers.
- # Provided strictly for compabitility and can be removed in Rails 5.
+ # Provided strictly for compatibility and can be removed in Rails 5.
def sanitizer_vendor
Rails::Html::Sanitizer
end
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index b8cb5bd746..37f2d7cad6 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -1577,7 +1577,7 @@ class FormHelperTest < ActionView::TestCase
"<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
- "<input name='commit' type='submit' value='Create post' />" +
+ "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" +
"<button name='button' type='submit'>Create post</button>" +
"<button name='button' type='submit'><span>Create post</span></button>"
end
@@ -1854,7 +1854,7 @@ class FormHelperTest < ActionView::TestCase
expected = whole_form("/posts/44", "edit_post_44", "edit_post", method: "patch") do
"<input name='post[title]' type='text' id='post_title' value='And his name will be forty and four.' />" +
- "<input name='commit' type='submit' value='Edit post' />"
+ "<input name='commit' data-disable-with='Edit post' type='submit' value='Edit post' />"
end
assert_dom_equal expected, output_buffer
@@ -1875,7 +1875,7 @@ class FormHelperTest < ActionView::TestCase
"<textarea name='other_name[body]' id='other_name_body'>\nBack to the hill and over it again!</textarea>" +
"<input name='other_name[secret]' value='0' type='hidden' />" +
"<input name='other_name[secret]' checked='checked' id='other_name_secret' value='1' type='checkbox' />" +
- "<input name='commit' value='Create post' type='submit' />"
+ "<input name='commit' value='Create post' data-disable-with='Create post' type='submit' />"
end
assert_dom_equal expected, output_buffer
@@ -2083,7 +2083,7 @@ class FormHelperTest < ActionView::TestCase
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
"<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
- "<input name='commit' type='submit' value='Create post' />"
+ "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
assert_dom_equal expected, output_buffer
@@ -2101,7 +2101,7 @@ class FormHelperTest < ActionView::TestCase
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
"<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
- "<input name='commit' type='submit' value='Create post' />"
+ "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
assert_dom_equal expected, output_buffer
@@ -2226,7 +2226,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts', 'new_post', 'new_post') do
- "<input name='commit' type='submit' value='Create Post' />"
+ "<input name='commit' data-disable-with='Create Post' type='submit' value='Create Post' />"
end
assert_dom_equal expected, output_buffer
@@ -2240,7 +2240,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
- "<input name='commit' type='submit' value='Confirm Post changes' />"
+ "<input name='commit' data-disable-with='Confirm Post changes' type='submit' value='Confirm Post changes' />"
end
assert_dom_equal expected, output_buffer
@@ -2254,7 +2254,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form do
- "<input name='commit' class='extra' type='submit' value='Save changes' />"
+ "<input name='commit' class='extra' data-disable-with='Save changes' type='submit' value='Save changes' />"
end
assert_dom_equal expected, output_buffer
@@ -2268,7 +2268,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts/123', 'edit_another_post', 'edit_another_post', method: 'patch') do
- "<input name='commit' type='submit' value='Update your Post' />"
+ "<input name='commit' data-disable-with='Update your Post' type='submit' value='Update your Post' />"
end
assert_dom_equal expected, output_buffer
diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb
index f602c82c42..a9d9562580 100644
--- a/actionview/test/template/form_tag_helper_test.rb
+++ b/actionview/test/template/form_tag_helper_test.rb
@@ -433,6 +433,44 @@ class FormTagHelperTest < ActionView::TestCase
)
end
+ def test_empty_submit_tag
+ assert_dom_equal(
+ %(<input data-disable-with="Save" name='commit' type="submit" value="Save" />),
+ submit_tag("Save")
+ )
+ end
+
+ def test_empty_submit_tag_with_opt_out
+ ActionView::Base.automatically_disable_submit_tag = false
+ assert_dom_equal(
+ %(<input name='commit' type="submit" value="Save" />),
+ submit_tag("Save")
+ )
+ ensure
+ ActionView::Base.automatically_disable_submit_tag = true
+ end
+
+ def test_data_disable_with_string
+ assert_dom_equal(
+ %(<input data-disable-with="Processing..." data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
+ submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" })
+ )
+ end
+
+ def test_data_disable_with_boolean
+ assert_dom_equal(
+ %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
+ submit_tag("Save", { "data-disable-with" => false, "data-confirm" => "Are you sure?" })
+ )
+ end
+
+ def test_data_hash_disable_with_boolean
+ assert_dom_equal(
+ %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
+ submit_tag("Save", { :data => { :confirm => "Are you sure?", :disable_with => false } })
+ )
+ end
+
def test_submit_tag_with_no_onclick_options
assert_dom_equal(
%(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />),
@@ -442,7 +480,7 @@ class FormTagHelperTest < ActionView::TestCase
def test_submit_tag_with_confirmation
assert_dom_equal(
- %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />),
+ %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" data-disable-with="Save" />),
submit_tag("Save", :data => { :confirm => "Are you sure?" })
)
end
diff --git a/actionview/test/template/test_case_test.rb b/actionview/test/template/test_case_test.rb
index 05c3dc0613..80fbaa8392 100644
--- a/actionview/test/template/test_case_test.rb
+++ b/actionview/test/template/test_case_test.rb
@@ -209,7 +209,7 @@ module ActionView
end
test "is able to use routes" do
- controller.request.assign_parameters(@routes, 'foo', 'index')
+ controller.request.assign_parameters(@routes, 'foo', 'index', {}, '/foo', [])
assert_equal '/foo', url_for
assert_equal '/bar', url_for(:controller => 'bar')
end
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index 74a12884ff..200d82838e 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -237,7 +237,7 @@ module ActiveJob
serialized_args.all? { |key, value| value == job[key] }
end
assert matching_job, "No enqueued job found with #{args}"
- instanciate_job(matching_job)
+ instantiate_job(matching_job)
ensure
queue_adapter.enqueued_jobs = original_enqueued_jobs + enqueued_jobs
end
@@ -259,7 +259,7 @@ module ActiveJob
serialized_args.all? { |key, value| value == job[key] }
end
assert matching_job, "No performed job found with #{args}"
- instanciate_job(matching_job)
+ instantiate_job(matching_job)
ensure
queue_adapter.performed_jobs = original_performed_jobs + performed_jobs
end
@@ -314,7 +314,7 @@ module ActiveJob
serialized_args
end
- def instanciate_job(payload)
+ def instantiate_job(payload)
job = payload[:job].new(*payload[:args])
job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at)
job.queue_name = payload[:queue]
diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb
index 4988cdb33f..d9938600f2 100644
--- a/activejob/test/support/integration/adapters/sidekiq.rb
+++ b/activejob/test/support/integration/adapters/sidekiq.rb
@@ -57,7 +57,7 @@ module SidekiqJobsManager
concurrency: 1,
timeout: 1,
})
- Sidekiq.poll_interval = 0.5
+ Sidekiq.average_scheduled_poll_interval = 0.5
Sidekiq::Scheduled.const_set :INITIAL_WAIT, 1
begin
sidekiq.run
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 47c275609e..df9704830e 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -451,6 +451,9 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`.
* `config.action_view.raise_on_missing_translations` determines whether an
error should be raised for missing translations.
+* `config.action_view.automatically_disable_submit_tag` determines whether
+ submit_tag should automatically disable on click, this defaults to true.
+
### Configuring Action Mailer
There are a number of settings available on `config.action_mailer`:
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 943074a3d4..3a691220cf 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -25,15 +25,7 @@ Rails tests can also simulate browser requests and thus you can test your applic
Introduction to Testing
-----------------------
-Testing support was woven into the Rails fabric from the beginning. It wasn't an "oh! let's bolt on support for running tests because they're new and cool" epiphany. Just about every Rails application interacts heavily with a database and, as a result, your tests will need a database to interact with as well. To write efficient tests, you'll need to understand how to set up this database and populate it with sample data.
-
-### The Test Environment
-
-By default, every Rails application has three environments: development, test, and production. The database for each one of them is configured in `config/database.yml`.
-
-A dedicated test database allows you to set up and interact with test data in isolation. This way your tests can mangle test data with confidence, without worrying about the data in the development or production databases.
-
-Also, each environment's configuration can be modified similarly. In this case, we can modify our test environment by changing the options found in `config/environments/test.rb`.
+Testing support was woven into the Rails fabric from the beginning. It wasn't an "oh! let's bolt on support for running tests because they're new and cool" epiphany.
### Rails Sets up for Testing from the Word Go
@@ -51,123 +43,18 @@ Fixtures are a way of organizing test data; they reside in the `fixtures` direct
The `test_helper.rb` file holds the default configuration for your tests.
-### The Low-Down on Fixtures
-
-For good tests, you'll need to give some thought to setting up test data.
-In Rails, you can handle this by defining and customizing fixtures.
-You can find comprehensive documentation in the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html).
-
-#### What Are Fixtures?
-
-_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and written in YAML. There is one file per model.
-
-You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model, Rails automatically creates fixture stubs in this directory.
-
-#### YAML
-
-YAML-formatted fixtures are a human-friendly way to describe your sample data. These types of fixtures have the **.yml** file extension (as in `users.yml`).
-
-Here's a sample YAML fixture file:
-
-```yaml
-# lo & behold! I am a YAML comment!
-david:
- name: David Heinemeier Hansson
- birthday: 1979-10-15
- profession: Systems development
-
-steve:
- name: Steve Ross Kellock
- birthday: 1974-09-27
- profession: guy with keyboard
-```
-
-Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are typically separated by a blank line. You can place comments in a fixture file by using the # character in the first column.
-
-If you are working with [associations](/association_basics.html), you can simply
-define a reference node between two different fixtures. Here's an example with
-a `belongs_to`/`has_many` association:
-
-```yaml
-# In fixtures/categories.yml
-about:
- name: About
-
-# In fixtures/articles.yml
-one:
- title: Welcome to Rails!
- body: Hello world!
- category: about
-```
-
-Notice the `category` key of the `one` article found in `fixtures/articles.yml` has a value of `about`. This tells Rails to load the category `about` found in `fixtures/categories.yml`.
-
-NOTE: For associations to reference one another by name, you cannot specify the `id:` attribute on the associated fixtures. Rails will auto assign a primary key to be consistent between runs. For more information on this association behavior please read the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html).
-
-#### ERB'in It Up
-
-ERB allows you to embed Ruby code within templates. The YAML fixture format is pre-processed with ERB when Rails loads fixtures. This allows you to use Ruby to help you generate some sample data. For example, the following code generates a thousand users:
-
-```erb
-<% 1000.times do |n| %>
-user_<%= n %>:
- username: <%= "user#{n}" %>
- email: <%= "user#{n}@example.com" %>
-<% end %>
-```
-#### Fixtures in Action
-
-Rails by default automatically loads all fixtures from the `test/fixtures` directory for your models and controllers test. Loading involves three steps:
-
-1. Remove any existing data from the table corresponding to the fixture
-2. Load the fixture data into the table
-3. Dump the fixture data into a method in case you want to access it directly
-
-TIP: In order to remove existing data from the database, Rails tries to disable referential integrity triggers (like foreign keys and check constraints). If you are getting annoying permission errors on running tests, make sure the database user has privilege to disable these triggers in testing environment. (In PostgreSQL, only superusers can disable all triggers. Read more about PostgreSQL permissions [here](http://blog.endpoint.com/2012/10/postgres-system-triggers-error.html))
-
-#### Fixtures are Active Record objects
-
-Fixtures are instances of Active Record. As mentioned in point #3 above, you can access the object directly because it is automatically available as a method whose scope is local of the test case. For example:
-
-```ruby
-# this will return the User object for the fixture named david
-users(:david)
-
-# this will return the property for david called id
-users(:david).id
-
-# one can also access methods available on the User class
-email(david.partner.email, david.location_tonight)
-```
-
-To get multiple fixtures at once, you can pass in a list of fixture names. For example:
-
-```ruby
-# this will return an array containing the fixtures david and steve
-users(:david, :steve)
-```
-
-### Console Tasks for Running your Tests
-
-Rails comes with a CLI command to run tests.
-Here are some examples of how to use it:
+### The Test Environment
-```bash
-$ bin/rails test # run all tests in the `test` directory
-$ bin/rails test test/controllers # run all tests from specific directory
-$ bin/rails test test/models/post_test.rb # run specific test
-$ bin/rails test test/models/post_test.rb:44 # run specific test and line
-```
+By default, every Rails application has three environments: development, test, and production.
-We will cover each of types Rails tests listed above in this guide.
+Each environment's configuration can be modified similarly. In this case, we can modify our test environment by changing the options found in `config/environments/test.rb`.
-Model Testing
-------------------------
+NOTE: Your test are run under RAILS_ENV=test.
-For this guide we will be using the application we built in the [Getting Started with Rails](getting_started.html) guide.
+### Rails meets Minitest
-If you remember when you used the `rails generate scaffold` command from earlier. We created our first resource among other things it created a test stub in the `test/models` directory:
+If you remember when you used the `rails generate scaffold` command from the [Getting Started with Rails](getting_started.html) guide. We created our first resource among other things it created test stubs in the `test` directory:
```bash
$ bin/rails generate scaffold article title:string body:text
@@ -178,14 +65,6 @@ create test/fixtures/articles.yml
...
```
-You can also generate the test stub for a model using the following command:
-
-```bash
-$ bin/rails generate test_unit:model article title:string body:text
-create test/models/article_test.rb
-create test/fixtures/articles.yml
-```
-
The default test stub in `test/models/article_test.rb` looks like this:
```ruby
@@ -250,47 +129,6 @@ An assertion is a line of code that evaluates an object (or expression) for expe
Every test must contain at least one assertion, with no restriction as to how many assertions are allowed. Only when all the assertions are successful will the test pass.
-### Maintaining the test database schema
-
-In order to run your tests, your test database will need to have the current
-structure. The test helper checks whether your test database has any pending
-migrations. If so, it will try to load your `db/schema.rb` or `db/structure.sql`
-into the test database. If migrations are still pending, an error will be
-raised. Usually this indicates that your schema is not fully migrated. Running
-the migrations against the development database (`bin/rake db:migrate`) will
-bring the schema up to date.
-
-NOTE: If existing migrations required modifications, the test database needs to
-be rebuilt. This can be done by executing `bin/rake db:test:prepare`.
-
-### Running Tests
-
-Running a test is as simple as invoking the file containing the test cases through `rails test` command.
-
-```bash
-$ bin/rails test test/models/article_test.rb
-.
-
-Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s.
-
-1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
-```
-
-This will run all test methods from the test case.
-
-You can also run a particular test method from the test case by running the test and providing the `test method name`.
-
-```bash
-$ bin/rails test test/models/article_test.rb test_the_truth
-.
-
-Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s.
-
-1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
-```
-
-The `.` (dot) above indicates a passing test. When a test fails you see an `F`; when a test throws an error you see an `E` in its place. The last line of the output is the summary.
-
#### Your first failing test
To see how a test failure is reported, you can add a failing test to the `article_test.rb` test case.
@@ -443,8 +281,8 @@ specify to make your test failure messages clearer. It's not required.
| `assert_no_match( regexp, string, [msg] )` | Ensures that a string doesn't match the regular expression.|
| `assert_includes( collection, obj, [msg] )` | Ensures that `obj` is in `collection`.|
| `assert_not_includes( collection, obj, [msg] )` | Ensures that `obj` is not in `collection`.|
-| `assert_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are within `delta` of each other.|
-| `assert_not_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are not within `delta` of each other.|
+| `assert_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are within `delta` of each other.|
+| `assert_not_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are not within `delta` of each other.|
| `assert_throws( symbol, [msg] ) { block }` | Ensures that the given block throws the symbol.|
| `assert_raises( exception1, exception2, ... ) { block }` | Ensures that the given block raises one of the given exceptions.|
| `assert_nothing_raised( exception1, exception2, ... ) { block }` | Ensures that the given block doesn't raise one of the given exceptions.|
@@ -485,7 +323,7 @@ Rails adds some custom assertions of its own to the `minitest` framework:
You'll see the usage of some of these assertions in the next chapter.
-### A Brief Note About Minitest
+### A Brief Note About Test Cases
All the basic assertions such as `assert_equal` defined in `Minitest::Assertions` are also available in the classes we use in our own test cases. In fact, Rails provides the following classes for you to inherit from:
@@ -500,6 +338,297 @@ Each of these classes include `Minitest::Assertions`, allowing us to use all of
NOTE: For more information on `Minitest`, refer to [Minitest](http://docs.seattlerb.org/minitest)
+### The Rails Test Runner
+
+We can run all of our tests at once by using the `rails test` command.
+
+Or we can run a single test by passing the `rails test` command the filename containing the test cases.
+
+```bash
+$ bin/rails test test/models/article_test.rb
+.
+
+Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s.
+
+1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
+```
+
+This will run all test methods from the test case.
+
+You can also run a particular test method from the test case by providing the `-n` or `--name` flag and the `test method name`.
+
+```bash
+$ bin/rails test test/models/article_test.rb -n test_the_truth
+.
+
+Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s.
+
+1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
+```
+
+You can also run a test at a specific line by providing the line number.
+
+```bash
+$ bin/rails test test/models/post_test.rb:44 # run specific test and line
+```
+
+You can also run an entire directory of tests by providing the path to the directory.
+
+```bash
+$ bin/rails test test/controllers # run all tests from specific directory
+```
+
+
+The Test Database
+-----------------
+
+Just about every Rails application interacts heavily with a database and, as a result, your tests will need a database to interact with as well. To write efficient tests, you'll need to understand how to set up this database and populate it with sample data.
+
+By default, every Rails application has three environments: development, test, and production. The database for each one of them is configured in `config/database.yml`.
+
+A dedicated test database allows you to set up and interact with test data in isolation. This way your tests can mangle test data with confidence, without worrying about the data in the development or production databases.
+
+
+### Maintaining the test database schema
+
+In order to run your tests, your test database will need to have the current
+structure. The test helper checks whether your test database has any pending
+migrations. If so, it will try to load your `db/schema.rb` or `db/structure.sql`
+into the test database. If migrations are still pending, an error will be
+raised. Usually this indicates that your schema is not fully migrated. Running
+the migrations against the development database (`bin/rake db:migrate`) will
+bring the schema up to date.
+
+NOTE: If existing migrations required modifications, the test database needs to
+be rebuilt. This can be done by executing `bin/rake db:test:prepare`.
+
+### The Low-Down on Fixtures
+
+For good tests, you'll need to give some thought to setting up test data.
+In Rails, you can handle this by defining and customizing fixtures.
+You can find comprehensive documentation in the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html).
+
+#### What Are Fixtures?
+
+_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and written in YAML. There is one file per model.
+
+You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model, Rails automatically creates fixture stubs in this directory.
+
+#### YAML
+
+YAML-formatted fixtures are a human-friendly way to describe your sample data. These types of fixtures have the **.yml** file extension (as in `users.yml`).
+
+Here's a sample YAML fixture file:
+
+```yaml
+# lo & behold! I am a YAML comment!
+david:
+ name: David Heinemeier Hansson
+ birthday: 1979-10-15
+ profession: Systems development
+
+steve:
+ name: Steve Ross Kellock
+ birthday: 1974-09-27
+ profession: guy with keyboard
+```
+
+Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are typically separated by a blank line. You can place comments in a fixture file by using the # character in the first column.
+
+If you are working with [associations](/association_basics.html), you can simply
+define a reference node between two different fixtures. Here's an example with
+a `belongs_to`/`has_many` association:
+
+```yaml
+# In fixtures/categories.yml
+about:
+ name: About
+
+# In fixtures/articles.yml
+one:
+ title: Welcome to Rails!
+ body: Hello world!
+ category: about
+```
+
+Notice the `category` key of the `one` article found in `fixtures/articles.yml` has a value of `about`. This tells Rails to load the category `about` found in `fixtures/categories.yml`.
+
+NOTE: For associations to reference one another by name, you cannot specify the `id:` attribute on the associated fixtures. Rails will auto assign a primary key to be consistent between runs. For more information on this association behavior please read the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html).
+
+#### ERB'in It Up
+
+ERB allows you to embed Ruby code within templates. The YAML fixture format is pre-processed with ERB when Rails loads fixtures. This allows you to use Ruby to help you generate some sample data. For example, the following code generates a thousand users:
+
+```erb
+<% 1000.times do |n| %>
+user_<%= n %>:
+ username: <%= "user#{n}" %>
+ email: <%= "user#{n}@example.com" %>
+<% end %>
+```
+
+#### Fixtures in Action
+
+Rails by default automatically loads all fixtures from the `test/fixtures` directory for your models and controllers test. Loading involves three steps:
+
+1. Remove any existing data from the table corresponding to the fixture
+2. Load the fixture data into the table
+3. Dump the fixture data into a method in case you want to access it directly
+
+TIP: In order to remove existing data from the database, Rails tries to disable referential integrity triggers (like foreign keys and check constraints). If you are getting annoying permission errors on running tests, make sure the database user has privilege to disable these triggers in testing environment. (In PostgreSQL, only superusers can disable all triggers. Read more about PostgreSQL permissions [here](http://blog.endpoint.com/2012/10/postgres-system-triggers-error.html))
+
+#### Fixtures are Active Record objects
+
+Fixtures are instances of Active Record. As mentioned in point #3 above, you can access the object directly because it is automatically available as a method whose scope is local of the test case. For example:
+
+```ruby
+# this will return the User object for the fixture named david
+users(:david)
+
+# this will return the property for david called id
+users(:david).id
+
+# one can also access methods available on the User class
+email(david.partner.email, david.location_tonight)
+```
+
+To get multiple fixtures at once, you can pass in a list of fixture names. For example:
+
+```ruby
+# this will return an array containing the fixtures david and steve
+users(:david, :steve)
+```
+
+
+Model Testing
+-------------
+
+Model tests are used to test the various models of your application.
+
+For creating Rails model tests, we use the 'test/model' directory for your application. Rails provides a generator to create an model test skeleton for you.
+
+```bash
+$ bin/rails generate test_unit:model article title:string body:text
+create test/models/article_test.rb
+create test/fixtures/articles.yml
+```
+
+Model tests don't have their own superclass like `ActionMailer::TestCase` instead they inherit from `ActiveSupport::TestCase`.
+
+
+Integration Testing
+-------------------
+
+Integration tests are used to test how various parts of your application interact. They are generally used to test important work flows within your application.
+
+For creating Rails integration tests, we use the 'test/integration' directory for your application. Rails provides a generator to create an integration test skeleton for you.
+
+```bash
+$ bin/rails generate integration_test user_flows
+ exists test/integration/
+ create test/integration/user_flows_test.rb
+```
+
+Here's what a freshly-generated integration test looks like:
+
+```ruby
+require 'test_helper'
+
+class UserFlowsTest < ActionDispatch::IntegrationTest
+ # test "the truth" do
+ # assert true
+ # end
+end
+```
+
+Inheriting from `ActionDispatch::IntegrationTest` comes with some advantages. This makes available some additional helpers to use in your integration tests.
+
+### Helpers Available for Integration Tests
+
+In addition to the standard testing helpers, inheriting `ActionDispatch::IntegrationTest` comes with some additional helpers available when writing integration tests. Let's briefly introduce you to the three categories of helpers you get to choose from.
+
+For dealing with the integration test runner, see [`ActionDispatch::Integration::Runner`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Runner.html).
+
+When performing requests, you will have [`ActionDispatch::Integration::RequestHelpers`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html) available for your use.
+
+If you'd like to modify the session, or state of your integration test you should look for [`ActionDispatch::Integration::Session`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Session.html) to help.
+
+### Implementing an integration test
+
+Let's add an integration test to our blog application. We'll start with a basic workflow of creating a new blog article, to verify that everything is working properly.
+
+We'll start by generating our integration test skeleton:
+
+```bash
+$ bin/rails generate integration_test blog_flow
+```
+
+It should have created a test file placeholder for us, with the output of the previous command you should see:
+
+```bash
+ invoke test_unit
+ create test/integration/blog_flow_test.rb
+```
+
+Now let's open that file and write our first assertion:
+
+```ruby
+require 'test_helper'
+
+class BlogFlowTest < ActionDispatch::IntegrationTest
+ test "can see the welcome page" do
+ get "/"
+ assert_select "h1", "Welcome#index"
+ end
+end
+```
+
+If you remember from earlier in the "Testing Views" section we covered `assert_select` to query the resulting HTML of a request.
+
+When visit our root path, we should see `welcome/index.html.erb` rendered for the view. So this assertion should pass.
+
+#### Creating articles integration
+
+How about testing our ability to create a new article in our blog and see the resulting article.
+
+```ruby
+test "can create an article" do
+ get "/articles/new"
+ assert_response :success
+
+ post "/articles",
+ params: { article: { title: "can create", body: "article successfully." } }
+ assert_response :redirect
+ follow_redirect!
+ assert_response :success
+ assert_select "p", "Title:\n can create"
+end
+```
+
+Let's break this test down so we can understand it.
+
+We start by calling the `:new` action on our Articles controller. This response should be successful.
+
+After this we make a post request to the `:create` action of our Articles controller:
+
+```ruby
+post "/articles",
+ params: { article: { title: "can create", body: "article successfully." } }
+assert_response :redirect
+follow_redirect!
+```
+
+The two lines following the request are to handle the redirect we setup when creating a new article.
+
+NOTE: Don't forget to call `follow_redirect!` if you plan to make subsequent requests after a redirect is made.
+
+Finally we can assert that our response was successful and our new article is readable on the page.
+
+#### Taking it further
+
+We were able to successfully test a very small workflow for visiting our blog and creating a new article. If we wanted to take this further we could add tests for commenting, removing articles, or editing comments. Integration tests are a great place to experiment with all kinds of use-cases for our applications.
+
+
Functional Tests for Your Controllers
-------------------------------------
@@ -530,7 +659,7 @@ Let me take you through one such test, `test_should_get_index` from the file `ar
```ruby
# articles_controller_test.rb
class ArticlesControllerTest < ActionController::TestCase
- test_should_get_index do
+ test "should get index" do
get :index
assert_response :success
assert_includes @response.body, 'Articles'
@@ -572,7 +701,7 @@ NOTE: If you try running `test_should_create_article` test from `articles_contro
Let us modify `test_should_create_article` test in `articles_controller_test.rb` so that all our test pass:
```ruby
-test_should_create_article do
+test "should create article" do
assert_difference('Article.count') do
post :create, params: { article: { title: 'Some title' } }
end
@@ -663,7 +792,7 @@ successfully creates a new Article.
Let's start by adding this assertion to our `test_should_create_article` test:
```ruby
-test_should_create_article do
+test "should create article" do
assert_difference('Article.count') do
post :create, params: { article: { title: 'Some title' } }
end
@@ -844,33 +973,7 @@ end
Testing Routes
--------------
-Like everything else in your Rails application, it is recommended that you test your routes. Below are example tests for the routes of default `show` and `create` action of `Articles` controller above and it should look like:
-
-```ruby
-class ArticleRoutesTest < ActionController::TestCase
- test "should route to article" do
- assert_routing '/articles/1', { controller: "articles", action: "show", id: "1" }
- end
-
- test "should route to create article" do
- assert_routing({ method: 'post', path: '/articles' }, { controller: "articles", action: "create" })
- end
-end
-```
-
-I've added this file here `test/controllers/articles_routes_test.rb` and if we run the test we should see:
-
-```bash
-$ bin/rails test test/controllers/articles_routes_test.rb
-
-# Running:
-
-..
-
-Finished in 0.069381s, 28.8263 runs/s, 86.4790 assertions/s.
-
-2 runs, 6 assertions, 0 failures, 0 errors, 0 skips
-```
+Like everything else in your Rails application, you can test your routes.
For more information on routing assertions available in Rails, see the API documentation for [`ActionDispatch::Assertions::RoutingAssertions`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html).
@@ -960,8 +1063,6 @@ have to use a mixin like this:
```ruby
class UserHelperTest < ActionView::TestCase
- include UserHelper
-
test "should return the user name" do
# ...
end
@@ -971,118 +1072,6 @@ end
Moreover, since the test class extends from `ActionView::TestCase`, you have
access to Rails' helper methods such as `link_to` or `pluralize`.
-Integration Testing
--------------------
-
-Integration tests are used to test how various parts of your application interact. They are generally used to test important work flows within your application.
-
-For creating Rails integration tests, we use the 'test/integration' directory for your application. Rails provides a generator to create an integration test skeleton for you.
-
-```bash
-$ bin/rails generate integration_test user_flows
- exists test/integration/
- create test/integration/user_flows_test.rb
-```
-
-Here's what a freshly-generated integration test looks like:
-
-```ruby
-require 'test_helper'
-
-class UserFlowsTest < ActionDispatch::IntegrationTest
- # test "the truth" do
- # assert true
- # end
-end
-```
-
-Inheriting from `ActionDispatch::IntegrationTest` comes with some advantages. This makes available some additional helpers to use in your integration tests.
-
-### Helpers Available for Integration Tests
-
-In addition to the standard testing helpers, inheriting `ActionDispatch::IntegrationTest` comes with some additional helpers available when writing integration tests. Let's briefly introduce you to the three categories of helpers you get to choose from.
-
-For dealing with the integration test runner, see [`ActionDispatch::Integration::Runner`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Runner.html).
-
-When performing requests, you will have [`ActionDispatch::Integration::RequestHelpers`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html) available for your use.
-
-If you'd like to modify the session, or state of your integration test you should look for [`ActionDispatch::Integration::Session`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Session.html) to help.
-
-### Implementing an integration test
-
-Let's add an integration test to our blog application. We'll start with a basic workflow of creating a new blog article, to verify that everything is working properly.
-
-We'll start by generating our integration test skeleton:
-
-```bash
-$ bin/rails generate integration_test blog_flow
-```
-
-It should have created a test file placeholder for us, with the output of the previous command you should see:
-
-```bash
- invoke test_unit
- create test/integration/blog_flow_test.rb
-```
-
-Now let's open that file and write our first assertion:
-
-```ruby
-require 'test_helper'
-
-class BlogFlowTest < ActionDispatch::IntegrationTest
- test "can see the welcome page" do
- get "/"
- assert_select "h1", "Welcome#index"
- end
-end
-```
-
-If you remember from earlier in the "Testing Views" section we covered `assert_select` to query the resulting HTML of a request.
-
-When visit our root path, we should see `welcome/index.html.erb` rendered for the view. So this assertion should pass.
-
-#### Creating articles integration
-
-How about testing our ability to create a new article in our blog and see the resulting article.
-
-```ruby
-test "can create an article" do
- get "/articles/new"
- assert_response :success
-
- post "/articles",
- params: { article: { title: "can create", body: "article successfully." } }
- assert_response :redirect
- follow_redirect!
- assert_response :success
- assert_select "p", "Title:\n can create"
-end
-```
-
-Let's break this test down so we can understand it.
-
-We start by calling the `:new` action on our Articles controller. This response should be successful.
-
-After this we make a post request to the `:create` action of our Articles controller:
-
-```ruby
-post "/articles",
- params: { article: { title: "can create", body: "article successfully." } }
-assert_response :redirect
-follow_redirect!
-```
-
-The two lines following the request are to handle the redirect we setup when creating a new article.
-
-NOTE: Don't forget to call `follow_redirect!` if you plan to make subsequent requests after a redirect is made.
-
-Finally we can assert that our response was successful and our new article is readable on the page.
-
-#### Taking it further
-
-We were able to successfully test a very small workflow for visiting our blog and creating a new article. If we wanted to take this further we could add tests for commenting, removing articles, or editing comments. Integration tests are a great place to experiment with all kinds of use-cases for our applications.
-
Testing Your Mailers
--------------------
@@ -1235,16 +1224,3 @@ class ProductTest < ActiveJob::TestCase
end
end
```
-
-Other Testing Approaches
-------------------------
-
-The built-in `minitest` based testing is not the only way to test Rails applications. Rails developers have come up with a wide variety of other approaches and aids for testing, including:
-
-* [NullDB](http://avdi.org/projects/nulldb/), a way to speed up testing by avoiding database use.
-* [Factory Girl](https://github.com/thoughtbot/factory_girl/tree/master), a replacement for fixtures.
-* [Fixture Builder](https://github.com/rdy/fixture_builder), a tool that compiles Ruby factories into fixtures before a test run.
-* [MiniTest::Spec Rails](https://github.com/metaskills/minitest-spec-rails), use the MiniTest::Spec DSL within your rails tests.
-* [Shoulda](http://www.thoughtbot.com/projects/shoulda), an extension to `test/unit` with additional helpers, macros, and assertions.
-* [RSpec](http://relishapp.com/rspec), a behavior-driven development framework
-* [Capybara](http://jnicklas.github.com/capybara/), Acceptance test framework for web applications
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 0f1aab9839..21adac272d 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Plugins generated using `rails plugin new` are now generated with the
+ version number set to 0.1.0.
+
+ *Daniel Morris*
+
+* `I18n.load_path` is now reloaded under development so there's no need to
+ restart the server to make new locale files available. Also, I18n will no
+ longer raise for deleted locale files.
+
+ *Kir Shatrov*
+
* Add `bin/update` script to update development environment automatically.
*Mehmet Emin İNAÇ*
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 8c09396fc1..0297ab75f6 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -51,7 +51,8 @@ Rails.application.configure do
# config.log_tags = [ :subdomain, :request_id ]
# Use a different logger for distributed setups.
- # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
+ # require 'syslog/logger'
+ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
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
index d257295988..b08f4ef9ae 100644
--- 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
@@ -1 +1 @@
-<%= wrap_in_modules 'VERSION = "0.0.1"' %>
+<%= wrap_in_modules "VERSION = '0.1.0'" %>
diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb
index 8a7aa6f50a..e47616a87f 100644
--- a/railties/lib/rails/paths.rb
+++ b/railties/lib/rails/paths.rb
@@ -123,8 +123,7 @@ module Rails
options[:load_path] ? load_path! : skip_load_path!
end
- # :nodoc:
- def absolute_current
+ def absolute_current # :nodoc:
File.expand_path(@current, @root.path)
end
@@ -180,8 +179,7 @@ module Rails
@paths
end
- # :nodoc:
- def extensions
+ def extensions # :nodoc:
$1.split(',') if @glob =~ /\{([\S]+)\}/
end
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index 1898691806..afccf9d885 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -323,7 +323,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
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/version.rb", /module Hyphenated\n module Name\n VERSION = '0.1.0'\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"/
@@ -342,7 +342,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
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/version.rb", /module MyHyphenated\n module Name\n VERSION = '0.1.0'\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"/
@@ -361,7 +361,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
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/version.rb", /module Deep\n module Hyphenated\n module Name\n VERSION = '0.1.0'\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"/