mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #5130 from dlee/revised_patch_verb
Add config.default_method_for_update to support PATCH
This commit is contained in:
commit
7f2548e34d
40 changed files with 402 additions and 151 deletions
1
Gemfile
1
Gemfile
|
@ -8,6 +8,7 @@ else
|
||||||
gem 'arel'
|
gem 'arel'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
gem 'rack-test', :git => "https://github.com/brynary/rack-test.git"
|
||||||
gem 'bcrypt-ruby', '~> 3.0.0'
|
gem 'bcrypt-ruby', '~> 3.0.0'
|
||||||
gem 'jquery-rails'
|
gem 'jquery-rails'
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ module ActionController
|
||||||
#
|
#
|
||||||
# An implementation might choose not to accept a previously used nonce or a previously used digest, in order to
|
# An implementation might choose not to accept a previously used nonce or a previously used digest, in order to
|
||||||
# protect against a replay attack. Or, an implementation might choose to use one-time nonces or digests for
|
# protect against a replay attack. Or, an implementation might choose to use one-time nonces or digests for
|
||||||
# POST or PUT requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
|
# POST, PUT, or PATCH requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
|
||||||
# of this document.
|
# of this document.
|
||||||
#
|
#
|
||||||
# The nonce is opaque to the client. Composed of Time, and hash of Time with secret
|
# The nonce is opaque to the client. Composed of Time, and hash of Time with secret
|
||||||
|
@ -293,7 +293,7 @@ module ActionController
|
||||||
end
|
end
|
||||||
|
|
||||||
# Might want a shorter timeout depending on whether the request
|
# Might want a shorter timeout depending on whether the request
|
||||||
# is a PUT or POST, and if client is browser or web service.
|
# is a PATCH, PUT, or POST, and if client is browser or web service.
|
||||||
# Can be much shorter if the Stale directive is implemented. This would
|
# Can be much shorter if the Stale directive is implemented. This would
|
||||||
# allow a user to use new nonce without prompting user again for their
|
# allow a user to use new nonce without prompting user again for their
|
||||||
# username and password.
|
# username and password.
|
||||||
|
|
|
@ -53,7 +53,7 @@ module ActionController #:nodoc:
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# The same happens for PUT and DELETE requests.
|
# The same happens for PATCH/PUT and DELETE requests.
|
||||||
#
|
#
|
||||||
# === Nested resources
|
# === Nested resources
|
||||||
#
|
#
|
||||||
|
@ -116,8 +116,9 @@ module ActionController #:nodoc:
|
||||||
class Responder
|
class Responder
|
||||||
attr_reader :controller, :request, :format, :resource, :resources, :options
|
attr_reader :controller, :request, :format, :resource, :resources, :options
|
||||||
|
|
||||||
ACTIONS_FOR_VERBS = {
|
DEFAULT_ACTIONS_FOR_VERBS = {
|
||||||
:post => :new,
|
:post => :new,
|
||||||
|
:patch => :edit,
|
||||||
:put => :edit
|
:put => :edit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +133,7 @@ module ActionController #:nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
delegate :head, :render, :redirect_to, :to => :controller
|
delegate :head, :render, :redirect_to, :to => :controller
|
||||||
delegate :get?, :post?, :put?, :delete?, :to => :request
|
delegate :get?, :post?, :patch?, :put?, :delete?, :to => :request
|
||||||
|
|
||||||
# Undefine :to_json and :to_yaml since it's defined on Object
|
# Undefine :to_json and :to_yaml since it's defined on Object
|
||||||
undef_method(:to_json) if method_defined?(:to_json)
|
undef_method(:to_json) if method_defined?(:to_json)
|
||||||
|
@ -259,11 +260,11 @@ module ActionController #:nodoc:
|
||||||
resource.respond_to?(:errors) && !resource.errors.empty?
|
resource.respond_to?(:errors) && !resource.errors.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
# By default, render the <code>:edit</code> action for HTML requests with failure, unless
|
# By default, render the <code>:edit</code> action for HTML requests with errors, unless
|
||||||
# the verb is POST.
|
# the verb was POST.
|
||||||
#
|
#
|
||||||
def default_action
|
def default_action
|
||||||
@action ||= ACTIONS_FOR_VERBS[request.request_method_symbol]
|
@action ||= DEFAULT_ACTIONS_FOR_VERBS[request.request_method_symbol]
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_errors
|
def resource_errors
|
||||||
|
|
|
@ -225,7 +225,7 @@ module ActionController
|
||||||
# == Basic example
|
# == Basic example
|
||||||
#
|
#
|
||||||
# Functional tests are written as follows:
|
# Functional tests are written as follows:
|
||||||
# 1. First, one uses the +get+, +post+, +put+, +delete+ or +head+ method to simulate
|
# 1. First, one uses the +get+, +post+, +patch+, +put+, +delete+ or +head+ method to simulate
|
||||||
# an HTTP request.
|
# an HTTP request.
|
||||||
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
||||||
# the controller's HTTP response, the database contents, etc.
|
# the controller's HTTP response, the database contents, etc.
|
||||||
|
@ -392,6 +392,11 @@ module ActionController
|
||||||
process(action, "POST", *args)
|
process(action, "POST", *args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a request simulating PATCH HTTP method and set/volley the response
|
||||||
|
def patch(action, *args)
|
||||||
|
process(action, "PATCH", *args)
|
||||||
|
end
|
||||||
|
|
||||||
# Executes a request simulating PUT HTTP method and set/volley the response
|
# Executes a request simulating PUT HTTP method and set/volley the response
|
||||||
def put(action, *args)
|
def put(action, *args)
|
||||||
process(action, "PUT", *args)
|
process(action, "PUT", *args)
|
||||||
|
|
|
@ -97,6 +97,12 @@ module ActionDispatch
|
||||||
HTTP_METHOD_LOOKUP[request_method] == :post
|
HTTP_METHOD_LOOKUP[request_method] == :post
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Is this a PATCH request?
|
||||||
|
# Equivalent to <tt>request.request_method == :patch</tt>.
|
||||||
|
def patch?
|
||||||
|
HTTP_METHOD_LOOKUP[request_method] == :patch
|
||||||
|
end
|
||||||
|
|
||||||
# Is this a PUT request?
|
# Is this a PUT request?
|
||||||
# Equivalent to <tt>request.request_method_symbol == :put</tt>.
|
# Equivalent to <tt>request.request_method_symbol == :put</tt>.
|
||||||
def put?
|
def put?
|
||||||
|
|
|
@ -23,6 +23,7 @@ module ActionDispatch
|
||||||
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
|
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
|
||||||
ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
|
ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
|
||||||
ActionDispatch::Response.default_charset = app.config.action_dispatch.default_charset || app.config.encoding
|
ActionDispatch::Response.default_charset = app.config.action_dispatch.default_charset || app.config.encoding
|
||||||
|
ActionDispatch::Routing::Mapper.default_method_for_update = app.config.default_method_for_update
|
||||||
|
|
||||||
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
|
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
|
||||||
ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates)
|
ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates)
|
||||||
|
|
|
@ -182,10 +182,13 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# == HTTP Methods
|
# == HTTP Methods
|
||||||
#
|
#
|
||||||
# Using the <tt>:via</tt> option when specifying a route allows you to restrict it to a specific HTTP method.
|
# Using the <tt>:via</tt> option when specifying a route allows you to
|
||||||
# Possible values are <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>.
|
# restrict it to a specific HTTP method. Possible values are <tt>:post</tt>,
|
||||||
# If your route needs to respond to more than one method you can use an array, e.g. <tt>[ :get, :post ]</tt>.
|
# <tt>:get</tt>, <tt>:patch</tt>, <tt>:put</tt>, <tt>:delete</tt> and
|
||||||
# The default value is <tt>:any</tt> which means that the route will respond to any of the HTTP methods.
|
# <tt>:any</tt>. If your route needs to respond to more than one method you
|
||||||
|
# can use an array, e.g. <tt>[ :get, :post ]</tt>. The default value is
|
||||||
|
# <tt>:any</tt> which means that the route will respond to any of the HTTP
|
||||||
|
# methods.
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
#
|
#
|
||||||
|
@ -198,7 +201,7 @@ module ActionDispatch
|
||||||
# === HTTP helper methods
|
# === HTTP helper methods
|
||||||
#
|
#
|
||||||
# An alternative method of specifying which HTTP method a route should respond to is to use the helper
|
# An alternative method of specifying which HTTP method a route should respond to is to use the helper
|
||||||
# methods <tt>get</tt>, <tt>post</tt>, <tt>put</tt> and <tt>delete</tt>.
|
# methods <tt>get</tt>, <tt>post</tt>, <tt>patch</tt>, <tt>put</tt> and <tt>delete</tt>.
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
#
|
#
|
||||||
|
@ -283,6 +286,6 @@ module ActionDispatch
|
||||||
autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
|
autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
|
||||||
|
|
||||||
SEPARATORS = %w( / . ? ) #:nodoc:
|
SEPARATORS = %w( / . ? ) #:nodoc:
|
||||||
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options] #:nodoc:
|
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] #:nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,8 @@ require 'action_dispatch/routing/redirection'
|
||||||
module ActionDispatch
|
module ActionDispatch
|
||||||
module Routing
|
module Routing
|
||||||
class Mapper
|
class Mapper
|
||||||
|
cattr_accessor(:default_method_for_update) {:put}
|
||||||
|
|
||||||
class Constraints #:nodoc:
|
class Constraints #:nodoc:
|
||||||
def self.new(app, constraints, request = Rack::Request)
|
def self.new(app, constraints, request = Rack::Request)
|
||||||
if constraints.any?
|
if constraints.any?
|
||||||
|
@ -465,7 +467,7 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
# get 'bacon', :to => 'food#bacon'
|
# get 'bacon', :to => 'food#bacon'
|
||||||
def get(*args, &block)
|
def get(*args, &block)
|
||||||
map_method(:get, args, &block)
|
map_method(:get, args, &block)
|
||||||
end
|
end
|
||||||
|
@ -475,17 +477,27 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
# post 'bacon', :to => 'food#bacon'
|
# post 'bacon', :to => 'food#bacon'
|
||||||
def post(*args, &block)
|
def post(*args, &block)
|
||||||
map_method(:post, args, &block)
|
map_method(:post, args, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a route that only recognizes HTTP PATCH.
|
||||||
|
# For supported arguments, see <tt>Base#match</tt>.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# patch 'bacon', :to => 'food#bacon'
|
||||||
|
def patch(*args, &block)
|
||||||
|
map_method(:patch, args, &block)
|
||||||
|
end
|
||||||
|
|
||||||
# Define a route that only recognizes HTTP PUT.
|
# Define a route that only recognizes HTTP PUT.
|
||||||
# For supported arguments, see <tt>Base#match</tt>.
|
# For supported arguments, see <tt>Base#match</tt>.
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
# put 'bacon', :to => 'food#bacon'
|
# put 'bacon', :to => 'food#bacon'
|
||||||
def put(*args, &block)
|
def put(*args, &block)
|
||||||
map_method(:put, args, &block)
|
map_method(:put, args, &block)
|
||||||
end
|
end
|
||||||
|
@ -495,7 +507,7 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
# delete 'broccoli', :to => 'food#broccoli'
|
# delete 'broccoli', :to => 'food#broccoli'
|
||||||
def delete(*args, &block)
|
def delete(*args, &block)
|
||||||
map_method(:delete, args, &block)
|
map_method(:delete, args, &block)
|
||||||
end
|
end
|
||||||
|
@ -522,13 +534,13 @@ module ActionDispatch
|
||||||
# This will create a number of routes for each of the posts and comments
|
# This will create a number of routes for each of the posts and comments
|
||||||
# controller. For <tt>Admin::PostsController</tt>, Rails will create:
|
# controller. For <tt>Admin::PostsController</tt>, Rails will create:
|
||||||
#
|
#
|
||||||
# GET /admin/posts
|
# GET /admin/posts
|
||||||
# GET /admin/posts/new
|
# GET /admin/posts/new
|
||||||
# POST /admin/posts
|
# POST /admin/posts
|
||||||
# GET /admin/posts/1
|
# GET /admin/posts/1
|
||||||
# GET /admin/posts/1/edit
|
# GET /admin/posts/1/edit
|
||||||
# PUT /admin/posts/1
|
# PUT/PATCH /admin/posts/1
|
||||||
# DELETE /admin/posts/1
|
# DELETE /admin/posts/1
|
||||||
#
|
#
|
||||||
# If you want to route /posts (without the prefix /admin) to
|
# If you want to route /posts (without the prefix /admin) to
|
||||||
# <tt>Admin::PostsController</tt>, you could use
|
# <tt>Admin::PostsController</tt>, you could use
|
||||||
|
@ -556,13 +568,13 @@ module ActionDispatch
|
||||||
# not use scope. In the last case, the following paths map to
|
# not use scope. In the last case, the following paths map to
|
||||||
# +PostsController+:
|
# +PostsController+:
|
||||||
#
|
#
|
||||||
# GET /admin/posts
|
# GET /admin/posts
|
||||||
# GET /admin/posts/new
|
# GET /admin/posts/new
|
||||||
# POST /admin/posts
|
# POST /admin/posts
|
||||||
# GET /admin/posts/1
|
# GET /admin/posts/1
|
||||||
# GET /admin/posts/1/edit
|
# GET /admin/posts/1/edit
|
||||||
# PUT /admin/posts/1
|
# PUT/PATCH /admin/posts/1
|
||||||
# DELETE /admin/posts/1
|
# DELETE /admin/posts/1
|
||||||
module Scoping
|
module Scoping
|
||||||
# Scopes a set of routes to the given default options.
|
# Scopes a set of routes to the given default options.
|
||||||
#
|
#
|
||||||
|
@ -651,13 +663,13 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# This generates the following routes:
|
# This generates the following routes:
|
||||||
#
|
#
|
||||||
# admin_posts GET /admin/posts(.:format) admin/posts#index
|
# admin_posts GET /admin/posts(.:format) admin/posts#index
|
||||||
# admin_posts POST /admin/posts(.:format) admin/posts#create
|
# admin_posts POST /admin/posts(.:format) admin/posts#create
|
||||||
# new_admin_post GET /admin/posts/new(.:format) admin/posts#new
|
# new_admin_post GET /admin/posts/new(.:format) admin/posts#new
|
||||||
# edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
|
# edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
|
||||||
# admin_post GET /admin/posts/:id(.:format) admin/posts#show
|
# admin_post GET /admin/posts/:id(.:format) admin/posts#show
|
||||||
# admin_post PUT /admin/posts/:id(.:format) admin/posts#update
|
# admin_post PUT/PATCH /admin/posts/:id(.:format) admin/posts#update
|
||||||
# admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
|
# admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
|
||||||
#
|
#
|
||||||
# === Options
|
# === Options
|
||||||
#
|
#
|
||||||
|
@ -972,12 +984,12 @@ module ActionDispatch
|
||||||
# the +GeoCoders+ controller (note that the controller is named after
|
# the +GeoCoders+ controller (note that the controller is named after
|
||||||
# the plural):
|
# the plural):
|
||||||
#
|
#
|
||||||
# GET /geocoder/new
|
# GET /geocoder/new
|
||||||
# POST /geocoder
|
# POST /geocoder
|
||||||
# GET /geocoder
|
# GET /geocoder
|
||||||
# GET /geocoder/edit
|
# GET /geocoder/edit
|
||||||
# PUT /geocoder
|
# PUT/PATCH /geocoder
|
||||||
# DELETE /geocoder
|
# DELETE /geocoder
|
||||||
#
|
#
|
||||||
# === Options
|
# === Options
|
||||||
# Takes same options as +resources+.
|
# Takes same options as +resources+.
|
||||||
|
@ -1002,8 +1014,10 @@ module ActionDispatch
|
||||||
member do
|
member do
|
||||||
get :edit if parent_resource.actions.include?(:edit)
|
get :edit if parent_resource.actions.include?(:edit)
|
||||||
get :show if parent_resource.actions.include?(:show)
|
get :show if parent_resource.actions.include?(:show)
|
||||||
put :update if parent_resource.actions.include?(:update)
|
|
||||||
delete :destroy if parent_resource.actions.include?(:destroy)
|
delete :destroy if parent_resource.actions.include?(:destroy)
|
||||||
|
if parent_resource.actions.include?(:update)
|
||||||
|
send default_method_for_update, :update
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1020,13 +1034,13 @@ module ActionDispatch
|
||||||
# creates seven different routes in your application, all mapping to
|
# creates seven different routes in your application, all mapping to
|
||||||
# the +Photos+ controller:
|
# the +Photos+ controller:
|
||||||
#
|
#
|
||||||
# GET /photos
|
# GET /photos
|
||||||
# GET /photos/new
|
# GET /photos/new
|
||||||
# POST /photos
|
# POST /photos
|
||||||
# GET /photos/:id
|
# GET /photos/:id
|
||||||
# GET /photos/:id/edit
|
# GET /photos/:id/edit
|
||||||
# PUT /photos/:id
|
# PUT/PATCH /photos/:id
|
||||||
# DELETE /photos/:id
|
# DELETE /photos/:id
|
||||||
#
|
#
|
||||||
# Resources can also be nested infinitely by using this block syntax:
|
# Resources can also be nested infinitely by using this block syntax:
|
||||||
#
|
#
|
||||||
|
@ -1036,13 +1050,13 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# This generates the following comments routes:
|
# This generates the following comments routes:
|
||||||
#
|
#
|
||||||
# GET /photos/:photo_id/comments
|
# GET /photos/:photo_id/comments
|
||||||
# GET /photos/:photo_id/comments/new
|
# GET /photos/:photo_id/comments/new
|
||||||
# POST /photos/:photo_id/comments
|
# POST /photos/:photo_id/comments
|
||||||
# GET /photos/:photo_id/comments/:id
|
# GET /photos/:photo_id/comments/:id
|
||||||
# GET /photos/:photo_id/comments/:id/edit
|
# GET /photos/:photo_id/comments/:id/edit
|
||||||
# PUT /photos/:photo_id/comments/:id
|
# PUT/PATCH /photos/:photo_id/comments/:id
|
||||||
# DELETE /photos/:photo_id/comments/:id
|
# DELETE /photos/:photo_id/comments/:id
|
||||||
#
|
#
|
||||||
# === Options
|
# === Options
|
||||||
# Takes same options as <tt>Base#match</tt> as well as:
|
# Takes same options as <tt>Base#match</tt> as well as:
|
||||||
|
@ -1104,13 +1118,13 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# The +comments+ resource here will have the following routes generated for it:
|
# The +comments+ resource here will have the following routes generated for it:
|
||||||
#
|
#
|
||||||
# post_comments GET /posts/:post_id/comments(.:format)
|
# post_comments GET /posts/:post_id/comments(.:format)
|
||||||
# post_comments POST /posts/:post_id/comments(.:format)
|
# post_comments POST /posts/:post_id/comments(.:format)
|
||||||
# new_post_comment GET /posts/:post_id/comments/new(.:format)
|
# new_post_comment GET /posts/:post_id/comments/new(.:format)
|
||||||
# edit_comment GET /sekret/comments/:id/edit(.:format)
|
# edit_comment GET /sekret/comments/:id/edit(.:format)
|
||||||
# comment GET /sekret/comments/:id(.:format)
|
# comment GET /sekret/comments/:id(.:format)
|
||||||
# comment PUT /sekret/comments/:id(.:format)
|
# comment PUT/PATCH /sekret/comments/:id(.:format)
|
||||||
# comment DELETE /sekret/comments/:id(.:format)
|
# comment DELETE /sekret/comments/:id(.:format)
|
||||||
#
|
#
|
||||||
# === Examples
|
# === Examples
|
||||||
#
|
#
|
||||||
|
@ -1138,11 +1152,14 @@ module ActionDispatch
|
||||||
get :new
|
get :new
|
||||||
end if parent_resource.actions.include?(:new)
|
end if parent_resource.actions.include?(:new)
|
||||||
|
|
||||||
|
# TODO: Only accept patch or put depending on config
|
||||||
member do
|
member do
|
||||||
get :edit if parent_resource.actions.include?(:edit)
|
get :edit if parent_resource.actions.include?(:edit)
|
||||||
get :show if parent_resource.actions.include?(:show)
|
get :show if parent_resource.actions.include?(:show)
|
||||||
put :update if parent_resource.actions.include?(:update)
|
|
||||||
delete :destroy if parent_resource.actions.include?(:destroy)
|
delete :destroy if parent_resource.actions.include?(:destroy)
|
||||||
|
if parent_resource.actions.include?(:update)
|
||||||
|
send default_method_for_update, :update
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,8 @@ module ActionDispatch
|
||||||
# object's <tt>@response</tt> instance variable will point to the same
|
# object's <tt>@response</tt> instance variable will point to the same
|
||||||
# response object.
|
# response object.
|
||||||
#
|
#
|
||||||
# You can also perform POST, PUT, DELETE, and HEAD requests with +#post+,
|
# You can also perform POST, PATCH, PUT, DELETE, and HEAD requests with
|
||||||
# +#put+, +#delete+, and +#head+.
|
# +#post+, +#patch+, +#put+, +#delete+, and +#head+.
|
||||||
def get(path, parameters = nil, headers = nil)
|
def get(path, parameters = nil, headers = nil)
|
||||||
process :get, path, parameters, headers
|
process :get, path, parameters, headers
|
||||||
end
|
end
|
||||||
|
@ -38,6 +38,12 @@ module ActionDispatch
|
||||||
process :post, path, parameters, headers
|
process :post, path, parameters, headers
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Performs a PATCH request with the given parameters. See +#get+ for more
|
||||||
|
# details.
|
||||||
|
def patch(path, parameters = nil, headers = nil)
|
||||||
|
process :patch, path, parameters, headers
|
||||||
|
end
|
||||||
|
|
||||||
# Performs a PUT request with the given parameters. See +#get+ for more
|
# Performs a PUT request with the given parameters. See +#get+ for more
|
||||||
# details.
|
# details.
|
||||||
def put(path, parameters = nil, headers = nil)
|
def put(path, parameters = nil, headers = nil)
|
||||||
|
@ -65,10 +71,10 @@ module ActionDispatch
|
||||||
# Performs an XMLHttpRequest request with the given parameters, mirroring
|
# Performs an XMLHttpRequest request with the given parameters, mirroring
|
||||||
# a request from the Prototype library.
|
# a request from the Prototype library.
|
||||||
#
|
#
|
||||||
# The request_method is +:get+, +:post+, +:put+, +:delete+ or +:head+; the
|
# The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or
|
||||||
# parameters are +nil+, a hash, or a url-encoded or multipart string;
|
# +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart
|
||||||
# the headers are a hash. Keys are automatically upcased and prefixed
|
# string; the headers are a hash. Keys are automatically upcased and
|
||||||
# with 'HTTP_' if not already.
|
# prefixed with 'HTTP_' if not already.
|
||||||
def xml_http_request(request_method, path, parameters = nil, headers = nil)
|
def xml_http_request(request_method, path, parameters = nil, headers = nil)
|
||||||
headers ||= {}
|
headers ||= {}
|
||||||
headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||||
|
@ -108,6 +114,12 @@ module ActionDispatch
|
||||||
request_via_redirect(:post, path, parameters, headers)
|
request_via_redirect(:post, path, parameters, headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Performs a PATCH request, following any subsequent redirect.
|
||||||
|
# See +request_via_redirect+ for more information.
|
||||||
|
def patch_via_redirect(path, parameters = nil, headers = nil)
|
||||||
|
request_via_redirect(:patch, path, parameters, headers)
|
||||||
|
end
|
||||||
|
|
||||||
# Performs a PUT request, following any subsequent redirect.
|
# Performs a PUT request, following any subsequent redirect.
|
||||||
# See +request_via_redirect+ for more information.
|
# See +request_via_redirect+ for more information.
|
||||||
def put_via_redirect(path, parameters = nil, headers = nil)
|
def put_via_redirect(path, parameters = nil, headers = nil)
|
||||||
|
@ -318,7 +330,7 @@ module ActionDispatch
|
||||||
@integration_session = Integration::Session.new(app)
|
@integration_session = Integration::Session.new(app)
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(get post put head delete options cookies assigns
|
%w(get post put patch head delete options cookies assigns
|
||||||
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
|
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
|
||||||
define_method(method) do |*args|
|
define_method(method) do |*args|
|
||||||
reset! unless integration_session
|
reset! unless integration_session
|
||||||
|
|
|
@ -132,6 +132,8 @@ module ActionView #:nodoc:
|
||||||
class Base
|
class Base
|
||||||
include Helpers, ::ERB::Util, Context
|
include Helpers, ::ERB::Util, Context
|
||||||
|
|
||||||
|
cattr_accessor(:default_method_for_update) {:put}
|
||||||
|
|
||||||
# Specify the proc used to decorate input tags that refer to attributes with errors.
|
# Specify the proc used to decorate input tags that refer to attributes with errors.
|
||||||
cattr_accessor :field_error_proc
|
cattr_accessor :field_error_proc
|
||||||
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
|
@@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
|
||||||
|
|
|
@ -250,7 +250,7 @@ module ActionView
|
||||||
#
|
#
|
||||||
# You can force the form to use the full array of HTTP verbs by setting
|
# You can force the form to use the full array of HTTP verbs by setting
|
||||||
#
|
#
|
||||||
# :method => (:get|:post|:put|:delete)
|
# :method => (:get|:post|:patch|:put|:delete)
|
||||||
#
|
#
|
||||||
# in the options hash. If the verb is not GET or POST, which are natively supported by HTML forms, the
|
# in the options hash. If the verb is not GET or POST, which are natively supported by HTML forms, the
|
||||||
# form will be set to POST and a hidden input called _method will carry the intended verb for the server
|
# form will be set to POST and a hidden input called _method will carry the intended verb for the server
|
||||||
|
@ -385,7 +385,7 @@ module ActionView
|
||||||
object = convert_to_model(object)
|
object = convert_to_model(object)
|
||||||
|
|
||||||
as = options[:as]
|
as = options[:as]
|
||||||
action, method = object.respond_to?(:persisted?) && object.persisted? ? [:edit, :put] : [:new, :post]
|
action, method = object.respond_to?(:persisted?) && object.persisted? ? [:edit, ActionView::Base.default_method_for_update] : [:new, :post]
|
||||||
options[:html].reverse_merge!(
|
options[:html].reverse_merge!(
|
||||||
:class => as ? "#{action}_#{as}" : dom_class(object, action),
|
:class => as ? "#{action}_#{as}" : dom_class(object, action),
|
||||||
:id => as ? "#{action}_#{as}" : [options[:namespace], dom_id(object, action)].compact.join("_").presence,
|
:id => as ? "#{action}_#{as}" : [options[:namespace], dom_id(object, action)].compact.join("_").presence,
|
||||||
|
|
|
@ -146,12 +146,12 @@ module ActionView
|
||||||
# create an HTML form and immediately submit the form for processing using
|
# create an HTML form and immediately submit the form for processing using
|
||||||
# the HTTP verb specified. Useful for having links perform a POST operation
|
# the HTTP verb specified. Useful for having links perform a POST operation
|
||||||
# in dangerous actions like deleting a record (which search bots can follow
|
# in dangerous actions like deleting a record (which search bots can follow
|
||||||
# while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt> and <tt>:put</tt>.
|
# while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>.
|
||||||
# Note that if the user has JavaScript disabled, the request will fall back
|
# Note that if the user has JavaScript disabled, the request will fall back
|
||||||
# to using GET. If <tt>:href => '#'</tt> is used and the user has JavaScript
|
# to using GET. If <tt>:href => '#'</tt> is used and the user has JavaScript
|
||||||
# disabled clicking the link will have no effect. If you are relying on the
|
# disabled clicking the link will have no effect. If you are relying on the
|
||||||
# POST behavior, you should check for it in your controller's action by using
|
# POST behavior, you should check for it in your controller's action by using
|
||||||
# the request object's methods for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
|
# the request object's methods for <tt>post?</tt>, <tt>delete?</tt>, <tt>:patch</tt>, or <tt>put?</tt>.
|
||||||
# * <tt>:remote => true</tt> - This will allow the unobtrusive JavaScript
|
# * <tt>:remote => true</tt> - This will allow the unobtrusive JavaScript
|
||||||
# driver to make an Ajax request to the URL in question instead of following
|
# driver to make an Ajax request to the URL in question instead of following
|
||||||
# the link. The drivers each provide mechanisms for listening for the
|
# the link. The drivers each provide mechanisms for listening for the
|
||||||
|
@ -272,7 +272,7 @@ module ActionView
|
||||||
#
|
#
|
||||||
# There are a few special +html_options+:
|
# There are a few special +html_options+:
|
||||||
# * <tt>:method</tt> - Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
|
# * <tt>:method</tt> - Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
|
||||||
# <tt>:delete</tt> and <tt>:put</tt>. By default it will be <tt>:post</tt>.
|
# <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
|
||||||
# * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
|
# * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
|
||||||
# * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
|
# * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
|
||||||
# prompt with the question specified. If the user accepts, the link is
|
# prompt with the question specified. If the user accepts, the link is
|
||||||
|
@ -329,7 +329,7 @@ module ActionView
|
||||||
remote = html_options.delete('remote')
|
remote = html_options.delete('remote')
|
||||||
|
|
||||||
method = html_options.delete('method').to_s
|
method = html_options.delete('method').to_s
|
||||||
method_tag = %w{put delete}.include?(method) ? method_tag(method) : ""
|
method_tag = %w{put patch delete}.include?(method) ? method_tag(method) : ""
|
||||||
|
|
||||||
form_method = method == 'get' ? 'get' : 'post'
|
form_method = method == 'get' ? 'get' : 'post'
|
||||||
form_options = html_options.delete('form') || {}
|
form_options = html_options.delete('form') || {}
|
||||||
|
|
|
@ -33,6 +33,7 @@ module ActionView
|
||||||
end
|
end
|
||||||
|
|
||||||
initializer "action_view.set_configs" do |app|
|
initializer "action_view.set_configs" do |app|
|
||||||
|
ActionView::Base.default_method_for_update = app.config.default_method_for_update
|
||||||
ActiveSupport.on_load(:action_view) do
|
ActiveSupport.on_load(:action_view) do
|
||||||
app.config.action_view.each do |k,v|
|
app.config.action_view.each do |k,v|
|
||||||
send "#{k}=", v
|
send "#{k}=", v
|
||||||
|
|
|
@ -180,7 +180,7 @@ class PageCachingTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
[:ok, :no_content, :found, :not_found].each do |status|
|
[:ok, :no_content, :found, :not_found].each do |status|
|
||||||
[:get, :post, :put, :delete].each do |method|
|
[:get, :post, :patch, :put, :delete].each do |method|
|
||||||
unless method == :get && status == :ok
|
unless method == :get && status == :ok
|
||||||
define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
|
define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
|
||||||
send(method, status)
|
send(method, status)
|
||||||
|
|
|
@ -63,6 +63,12 @@ class SessionTest < ActiveSupport::TestCase
|
||||||
@session.post_via_redirect(path, args, headers)
|
@session.post_via_redirect(path, args, headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_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)
|
||||||
|
end
|
||||||
|
|
||||||
def test_put_via_redirect
|
def test_put_via_redirect
|
||||||
path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" }
|
path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" }
|
||||||
@session.expects(:request_via_redirect).with(:put, path, args, headers)
|
@session.expects(:request_via_redirect).with(:put, path, args, headers)
|
||||||
|
@ -87,6 +93,12 @@ class SessionTest < ActiveSupport::TestCase
|
||||||
@session.post(path,params,headers)
|
@session.post(path,params,headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_patch
|
||||||
|
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||||
|
@session.expects(:process).with(:patch,path,params,headers)
|
||||||
|
@session.patch(path,params,headers)
|
||||||
|
end
|
||||||
|
|
||||||
def test_put
|
def test_put
|
||||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||||
@session.expects(:process).with(:put,path,params,headers)
|
@session.expects(:process).with(:put,path,params,headers)
|
||||||
|
@ -131,6 +143,16 @@ class SessionTest < ActiveSupport::TestCase
|
||||||
@session.xml_http_request(:post,path,params,headers)
|
@session.xml_http_request(:post,path,params,headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_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,headers_after_xhr)
|
||||||
|
@session.xml_http_request(:patch,path,params,headers)
|
||||||
|
end
|
||||||
|
|
||||||
def test_xml_http_request_put
|
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(
|
headers_after_xhr = headers.merge(
|
||||||
|
@ -228,7 +250,7 @@ class IntegrationTestUsesCorrectClass < ActionDispatch::IntegrationTest
|
||||||
@integration_session.stubs(:generic_url_rewriter)
|
@integration_session.stubs(:generic_url_rewriter)
|
||||||
@integration_session.stubs(:process)
|
@integration_session.stubs(:process)
|
||||||
|
|
||||||
%w( get post head put delete options ).each do |verb|
|
%w( get post head patch put delete options ).each do |verb|
|
||||||
assert_nothing_raised("'#{verb}' should use integration test methods") { __send__(verb, '/') }
|
assert_nothing_raised("'#{verb}' should use integration test methods") { __send__(verb, '/') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -770,6 +770,41 @@ class RespondWithControllerTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_using_resource_for_patch_with_html_redirects_on_success
|
||||||
|
with_test_route_set do
|
||||||
|
patch :using_resource
|
||||||
|
assert_equal "text/html", @response.content_type
|
||||||
|
assert_equal 302, @response.status
|
||||||
|
assert_equal "http://www.example.com/customers/13", @response.location
|
||||||
|
assert @response.redirect?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_using_resource_for_patch_with_html_rerender_on_failure
|
||||||
|
with_test_route_set do
|
||||||
|
errors = { :name => :invalid }
|
||||||
|
Customer.any_instance.stubs(:errors).returns(errors)
|
||||||
|
patch :using_resource
|
||||||
|
assert_equal "text/html", @response.content_type
|
||||||
|
assert_equal 200, @response.status
|
||||||
|
assert_equal "Edit world!\n", @response.body
|
||||||
|
assert_nil @response.location
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_using_resource_for_patch_with_html_rerender_on_failure_even_on_method_override
|
||||||
|
with_test_route_set do
|
||||||
|
errors = { :name => :invalid }
|
||||||
|
Customer.any_instance.stubs(:errors).returns(errors)
|
||||||
|
@request.env["rack.methodoverride.original_method"] = "POST"
|
||||||
|
patch :using_resource
|
||||||
|
assert_equal "text/html", @response.content_type
|
||||||
|
assert_equal 200, @response.status
|
||||||
|
assert_equal "Edit world!\n", @response.body
|
||||||
|
assert_nil @response.location
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_using_resource_for_put_with_html_redirects_on_success
|
def test_using_resource_for_put_with_html_redirects_on_success
|
||||||
with_test_route_set do
|
with_test_route_set do
|
||||||
put :using_resource
|
put :using_resource
|
||||||
|
|
|
@ -114,6 +114,10 @@ module RequestForgeryProtectionTests
|
||||||
assert_blocked { post :index, :format=>'xml' }
|
assert_blocked { post :index, :format=>'xml' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_should_not_allow_patch_without_token
|
||||||
|
assert_blocked { patch :index }
|
||||||
|
end
|
||||||
|
|
||||||
def test_should_not_allow_put_without_token
|
def test_should_not_allow_put_without_token
|
||||||
assert_blocked { put :index }
|
assert_blocked { put :index }
|
||||||
end
|
end
|
||||||
|
@ -130,6 +134,10 @@ module RequestForgeryProtectionTests
|
||||||
assert_not_blocked { post :index, :custom_authenticity_token => @token }
|
assert_not_blocked { post :index, :custom_authenticity_token => @token }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_should_allow_patch_with_token
|
||||||
|
assert_not_blocked { patch :index, :custom_authenticity_token => @token }
|
||||||
|
end
|
||||||
|
|
||||||
def test_should_allow_put_with_token
|
def test_should_allow_put_with_token
|
||||||
assert_not_blocked { put :index, :custom_authenticity_token => @token }
|
assert_not_blocked { put :index, :custom_authenticity_token => @token }
|
||||||
end
|
end
|
||||||
|
@ -148,6 +156,11 @@ module RequestForgeryProtectionTests
|
||||||
assert_not_blocked { delete :index }
|
assert_not_blocked { delete :index }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_should_allow_patch_with_token_in_header
|
||||||
|
@request.env['HTTP_X_CSRF_TOKEN'] = @token
|
||||||
|
assert_not_blocked { patch :index }
|
||||||
|
end
|
||||||
|
|
||||||
def test_should_allow_put_with_token_in_header
|
def test_should_allow_put_with_token_in_header
|
||||||
@request.env['HTTP_X_CSRF_TOKEN'] = @token
|
@request.env['HTTP_X_CSRF_TOKEN'] = @token
|
||||||
assert_not_blocked { put :index }
|
assert_not_blocked { put :index }
|
||||||
|
@ -232,7 +245,7 @@ class FreeCookieControllerTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_allow_all_methods_without_token
|
def test_should_allow_all_methods_without_token
|
||||||
[:post, :put, :delete].each do |method|
|
[:post, :patch, :put, :delete].each do |method|
|
||||||
assert_nothing_raised { send(method, :index)}
|
assert_nothing_raised { send(method, :index)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -158,7 +158,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_collection_actions
|
def test_with_collection_actions
|
||||||
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete }
|
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete, 'e' => :patch }
|
||||||
|
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do
|
set.draw do
|
||||||
|
@ -167,6 +167,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
put :b, :on => :collection
|
put :b, :on => :collection
|
||||||
post :c, :on => :collection
|
post :c, :on => :collection
|
||||||
delete :d, :on => :collection
|
delete :d, :on => :collection
|
||||||
|
patch :e, :on => :collection
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -185,7 +186,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_collection_actions_and_name_prefix
|
def test_with_collection_actions_and_name_prefix
|
||||||
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete }
|
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete, 'e' => :patch }
|
||||||
|
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do
|
set.draw do
|
||||||
|
@ -195,6 +196,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
put :b, :on => :collection
|
put :b, :on => :collection
|
||||||
post :c, :on => :collection
|
post :c, :on => :collection
|
||||||
delete :d, :on => :collection
|
delete :d, :on => :collection
|
||||||
|
patch :e, :on => :collection
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -241,7 +243,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_collection_action_and_name_prefix_and_formatted
|
def test_with_collection_action_and_name_prefix_and_formatted
|
||||||
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete }
|
actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete, 'e' => :patch }
|
||||||
|
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do
|
set.draw do
|
||||||
|
@ -251,6 +253,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
put :b, :on => :collection
|
put :b, :on => :collection
|
||||||
post :c, :on => :collection
|
post :c, :on => :collection
|
||||||
delete :d, :on => :collection
|
delete :d, :on => :collection
|
||||||
|
patch :e, :on => :collection
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -270,7 +273,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_member_action
|
def test_with_member_action
|
||||||
[:put, :post].each do |method|
|
[:patch, :put, :post].each do |method|
|
||||||
with_restful_routing :messages, :member => { :mark => method } do
|
with_restful_routing :messages, :member => { :mark => method } do
|
||||||
mark_options = {:action => 'mark', :id => '1'}
|
mark_options = {:action => 'mark', :id => '1'}
|
||||||
mark_path = "/messages/1/mark"
|
mark_path = "/messages/1/mark"
|
||||||
|
@ -294,7 +297,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_member_when_override_paths_for_default_restful_actions_with
|
def test_member_when_override_paths_for_default_restful_actions_with
|
||||||
[:put, :post].each do |method|
|
[:patch, :put, :post].each do |method|
|
||||||
with_restful_routing :messages, :member => { :mark => method }, :path_names => {:new => 'nuevo'} do
|
with_restful_routing :messages, :member => { :mark => method }, :path_names => {:new => 'nuevo'} do
|
||||||
mark_options = {:action => 'mark', :id => '1', :controller => "messages"}
|
mark_options = {:action => 'mark', :id => '1', :controller => "messages"}
|
||||||
mark_path = "/messages/1/mark"
|
mark_path = "/messages/1/mark"
|
||||||
|
@ -311,7 +314,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_two_member_actions_with_same_method
|
def test_with_two_member_actions_with_same_method
|
||||||
[:put, :post].each do |method|
|
[:patch, :put, :post].each do |method|
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do
|
set.draw do
|
||||||
resources :messages do
|
resources :messages do
|
||||||
|
@ -564,7 +567,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_singleton_resource_with_member_action
|
def test_singleton_resource_with_member_action
|
||||||
[:put, :post].each do |method|
|
[:patch, :put, :post].each do |method|
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do
|
set.draw do
|
||||||
resource :account do
|
resource :account do
|
||||||
|
@ -586,7 +589,7 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_singleton_resource_with_two_member_actions_with_same_method
|
def test_singleton_resource_with_two_member_actions_with_same_method
|
||||||
[:put, :post].each do |method|
|
[:patch, :put, :post].each do |method|
|
||||||
with_routing do |set|
|
with_routing do |set|
|
||||||
set.draw do
|
set.draw do
|
||||||
resource :account do
|
resource :account do
|
||||||
|
@ -651,12 +654,16 @@ class ResourcesTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_not_allow_delete_or_put_on_collection_path
|
def test_should_not_allow_delete_or_patch_or_put_on_collection_path
|
||||||
controller_name = :messages
|
controller_name = :messages
|
||||||
with_restful_routing controller_name do
|
with_restful_routing controller_name do
|
||||||
options = { :controller => controller_name.to_s }
|
options = { :controller => controller_name.to_s }
|
||||||
collection_path = "/#{controller_name}"
|
collection_path = "/#{controller_name}"
|
||||||
|
|
||||||
|
assert_raise(ActionController::RoutingError) do
|
||||||
|
assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :patch)
|
||||||
|
end
|
||||||
|
|
||||||
assert_raise(ActionController::RoutingError) do
|
assert_raise(ActionController::RoutingError) do
|
||||||
assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put)
|
assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put)
|
||||||
end
|
end
|
||||||
|
|
|
@ -648,11 +648,12 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
|
||||||
match '/match' => 'books#get', :via => :get
|
match '/match' => 'books#get', :via => :get
|
||||||
match '/match' => 'books#post', :via => :post
|
match '/match' => 'books#post', :via => :post
|
||||||
match '/match' => 'books#put', :via => :put
|
match '/match' => 'books#put', :via => :put
|
||||||
|
match '/match' => 'books#patch', :via => :patch
|
||||||
match '/match' => 'books#delete', :via => :delete
|
match '/match' => 'books#delete', :via => :delete
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(GET POST PUT DELETE).each do |request_method|
|
%w(GET PATCH POST PUT DELETE).each do |request_method|
|
||||||
define_method("test_request_method_recognized_with_#{request_method}") do
|
define_method("test_request_method_recognized_with_#{request_method}") do
|
||||||
setup_request_method_routes_for(request_method)
|
setup_request_method_routes_for(request_method)
|
||||||
params = rs.recognize_path("/match", :method => request_method)
|
params = rs.recognize_path("/match", :method => request_method)
|
||||||
|
@ -1035,6 +1036,7 @@ class RouteSetTest < ActiveSupport::TestCase
|
||||||
post "/people" => "people#create"
|
post "/people" => "people#create"
|
||||||
get "/people/:id" => "people#show", :as => "person"
|
get "/people/:id" => "people#show", :as => "person"
|
||||||
put "/people/:id" => "people#update"
|
put "/people/:id" => "people#update"
|
||||||
|
patch "/people/:id" => "people#update"
|
||||||
delete "/people/:id" => "people#destroy"
|
delete "/people/:id" => "people#destroy"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1047,6 +1049,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
||||||
params = set.recognize_path("/people/5", :method => :put)
|
params = set.recognize_path("/people/5", :method => :put)
|
||||||
assert_equal("update", params[:action])
|
assert_equal("update", params[:action])
|
||||||
|
|
||||||
|
params = set.recognize_path("/people/5", :method => :patch)
|
||||||
|
assert_equal("update", params[:action])
|
||||||
|
|
||||||
assert_raise(ActionController::UnknownHttpMethod) {
|
assert_raise(ActionController::UnknownHttpMethod) {
|
||||||
set.recognize_path("/people", :method => :bacon)
|
set.recognize_path("/people", :method => :bacon)
|
||||||
}
|
}
|
||||||
|
@ -1059,6 +1064,10 @@ class RouteSetTest < ActiveSupport::TestCase
|
||||||
assert_equal("update", params[:action])
|
assert_equal("update", params[:action])
|
||||||
assert_equal("5", params[:id])
|
assert_equal("5", params[:id])
|
||||||
|
|
||||||
|
params = set.recognize_path("/people/5", :method => :patch)
|
||||||
|
assert_equal("update", params[:action])
|
||||||
|
assert_equal("5", params[:id])
|
||||||
|
|
||||||
params = set.recognize_path("/people/5", :method => :delete)
|
params = set.recognize_path("/people/5", :method => :delete)
|
||||||
assert_equal("destroy", params[:action])
|
assert_equal("destroy", params[:action])
|
||||||
assert_equal("5", params[:id])
|
assert_equal("5", params[:id])
|
||||||
|
@ -1112,6 +1121,7 @@ class RouteSetTest < ActiveSupport::TestCase
|
||||||
set.draw do
|
set.draw do
|
||||||
get "people/:id" => "people#show", :as => "person"
|
get "people/:id" => "people#show", :as => "person"
|
||||||
put "people/:id" => "people#update"
|
put "people/:id" => "people#update"
|
||||||
|
patch "people/:id" => "people#update"
|
||||||
get "people/:id(.:format)" => "people#show"
|
get "people/:id(.:format)" => "people#show"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1122,6 +1132,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
||||||
params = set.recognize_path("/people/5", :method => :put)
|
params = set.recognize_path("/people/5", :method => :put)
|
||||||
assert_equal("update", params[:action])
|
assert_equal("update", params[:action])
|
||||||
|
|
||||||
|
params = set.recognize_path("/people/5", :method => :patch)
|
||||||
|
assert_equal("update", params[:action])
|
||||||
|
|
||||||
params = set.recognize_path("/people/5.png", :method => :get)
|
params = set.recognize_path("/people/5.png", :method => :get)
|
||||||
assert_equal("show", params[:action])
|
assert_equal("show", params[:action])
|
||||||
assert_equal("5", params[:id])
|
assert_equal("5", params[:id])
|
||||||
|
|
|
@ -325,14 +325,14 @@ class RequestTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test "String request methods" do
|
test "String request methods" do
|
||||||
[:get, :post, :put, :delete].each do |method|
|
[:get, :post, :patch, :put, :delete].each do |method|
|
||||||
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
|
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
|
||||||
assert_equal method.to_s.upcase, request.method
|
assert_equal method.to_s.upcase, request.method
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Symbol forms of request methods via method_symbol" do
|
test "Symbol forms of request methods via method_symbol" do
|
||||||
[:get, :post, :put, :delete].each do |method|
|
[:get, :post, :patch, :put, :delete].each do |method|
|
||||||
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
|
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
|
||||||
assert_equal method, request.method_symbol
|
assert_equal method, request.method_symbol
|
||||||
end
|
end
|
||||||
|
@ -346,7 +346,7 @@ class RequestTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test "allow method hacking on post" do
|
test "allow method hacking on post" do
|
||||||
%w(GET OPTIONS PUT POST DELETE).each do |method|
|
%w(GET OPTIONS PATCH PUT POST DELETE).each do |method|
|
||||||
request = stub_request "REQUEST_METHOD" => method.to_s.upcase
|
request = stub_request "REQUEST_METHOD" => method.to_s.upcase
|
||||||
assert_equal(method == "HEAD" ? "GET" : method, request.method)
|
assert_equal(method == "HEAD" ? "GET" : method, request.method)
|
||||||
end
|
end
|
||||||
|
@ -360,7 +360,7 @@ class RequestTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test "restrict method hacking" do
|
test "restrict method hacking" do
|
||||||
[:get, :put, :delete].each do |method|
|
[:get, :patch, :put, :delete].each do |method|
|
||||||
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase,
|
request = stub_request 'REQUEST_METHOD' => method.to_s.upcase,
|
||||||
'action_dispatch.request.request_parameters' => { :_method => 'put' }
|
'action_dispatch.request.request_parameters' => { :_method => 'put' }
|
||||||
assert_equal method.to_s.upcase, request.method
|
assert_equal method.to_s.upcase, request.method
|
||||||
|
@ -375,6 +375,13 @@ class RequestTest < ActiveSupport::TestCase
|
||||||
assert request.head?
|
assert request.head?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "post masquerading as patch" do
|
||||||
|
request = stub_request 'REQUEST_METHOD' => 'PATCH', "rack.methodoverride.original_method" => "POST"
|
||||||
|
assert_equal "POST", request.method
|
||||||
|
assert_equal "PATCH", request.request_method
|
||||||
|
assert request.patch?
|
||||||
|
end
|
||||||
|
|
||||||
test "post masquerading as put" do
|
test "post masquerading as put" do
|
||||||
request = stub_request 'REQUEST_METHOD' => 'PUT', "rack.methodoverride.original_method" => "POST"
|
request = stub_request 'REQUEST_METHOD' => 'PUT', "rack.methodoverride.original_method" => "POST"
|
||||||
assert_equal "POST", request.method
|
assert_equal "POST", request.method
|
||||||
|
|
|
@ -2195,6 +2195,15 @@ class FormHelperTest < ActionView::TestCase
|
||||||
assert_equal expected, output_buffer
|
assert_equal expected, output_buffer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_form_for_with_default_method_as_patch
|
||||||
|
ActionView::Base.default_method_for_update = :patch
|
||||||
|
form_for(@post) {}
|
||||||
|
expected = whole_form("/posts/123", "edit_post_123", "edit_post", "patch")
|
||||||
|
assert_dom_equal expected, output_buffer
|
||||||
|
ensure
|
||||||
|
ActionView::Base.default_method_for_update = :put
|
||||||
|
end
|
||||||
|
|
||||||
def test_fields_for_returns_block_result
|
def test_fields_for_returns_block_result
|
||||||
output = fields_for(Post.new) { |f| "fields" }
|
output = fields_for(Post.new) { |f| "fields" }
|
||||||
assert_equal "fields", output
|
assert_equal "fields", output
|
||||||
|
|
|
@ -78,6 +78,12 @@ class FormTagHelperTest < ActionView::TestCase
|
||||||
assert_dom_equal expected, actual
|
assert_dom_equal expected, actual
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_form_tag_with_method_patch
|
||||||
|
actual = form_tag({}, { :method => :patch })
|
||||||
|
expected = whole_form("http://www.example.com", :method => :patch)
|
||||||
|
assert_dom_equal expected, actual
|
||||||
|
end
|
||||||
|
|
||||||
def test_form_tag_with_method_put
|
def test_form_tag_with_method_put
|
||||||
actual = form_tag({}, { :method => :put })
|
actual = form_tag({}, { :method => :put })
|
||||||
expected = whole_form("http://www.example.com", :method => :put)
|
expected = whole_form("http://www.example.com", :method => :put)
|
||||||
|
|
|
@ -62,9 +62,9 @@ module ActiveModel
|
||||||
#
|
#
|
||||||
# Returns a boolean that specifies whether the object has been persisted yet.
|
# Returns a boolean that specifies whether the object has been persisted yet.
|
||||||
# This is used when calculating the URL for an object. If the object is
|
# This is used when calculating the URL for an object. If the object is
|
||||||
# not persisted, a form for that object, for instance, will be POSTed to the
|
# not persisted, a form for that object, for instance, will route to the
|
||||||
# collection. If it is persisted, a form for the object will be PUT to the
|
# create action. If it is persisted, a form for the object will routes to
|
||||||
# URL for the object.
|
# the update action.
|
||||||
def test_persisted?
|
def test_persisted?
|
||||||
assert model.respond_to?(:persisted?), "The model should respond to persisted?"
|
assert model.respond_to?(:persisted?), "The model should respond to persisted?"
|
||||||
assert_boolean model.persisted?, "persisted?"
|
assert_boolean model.persisted?, "persisted?"
|
||||||
|
|
|
@ -15,6 +15,7 @@ module ActiveResource
|
||||||
HTTP_FORMAT_HEADER_NAMES = { :get => 'Accept',
|
HTTP_FORMAT_HEADER_NAMES = { :get => 'Accept',
|
||||||
:put => 'Content-Type',
|
:put => 'Content-Type',
|
||||||
:post => 'Content-Type',
|
:post => 'Content-Type',
|
||||||
|
:patch => 'Content-Type',
|
||||||
:delete => 'Accept',
|
:delete => 'Accept',
|
||||||
:head => 'Accept'
|
:head => 'Accept'
|
||||||
}
|
}
|
||||||
|
@ -86,6 +87,12 @@ module ActiveResource
|
||||||
with_auth { request(:delete, path, build_request_headers(headers, :delete, self.site.merge(path))) }
|
with_auth { request(:delete, path, build_request_headers(headers, :delete, self.site.merge(path))) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a PATCH request (see HTTP protocol documentation if unfamiliar).
|
||||||
|
# Used to update resources.
|
||||||
|
def patch(path, body = '', headers = {})
|
||||||
|
with_auth { request(:patch, path, body.to_s, build_request_headers(headers, :patch, self.site.merge(path))) }
|
||||||
|
end
|
||||||
|
|
||||||
# Executes a PUT request (see HTTP protocol documentation if unfamiliar).
|
# Executes a PUT request (see HTTP protocol documentation if unfamiliar).
|
||||||
# Used to update resources.
|
# Used to update resources.
|
||||||
def put(path, body = '', headers = {})
|
def put(path, body = '', headers = {})
|
||||||
|
|
|
@ -11,10 +11,10 @@ module ActiveResource
|
||||||
#
|
#
|
||||||
# This route set creates routes for the following HTTP requests:
|
# This route set creates routes for the following HTTP requests:
|
||||||
#
|
#
|
||||||
# POST /people/new/register.json # PeopleController.register
|
# POST /people/new/register.json # PeopleController.register
|
||||||
# PUT /people/1/promote.json # PeopleController.promote with :id => 1
|
# PUT/PATCH /people/1/promote.json # PeopleController.promote with :id => 1
|
||||||
# DELETE /people/1/deactivate.json # PeopleController.deactivate with :id => 1
|
# DELETE /people/1/deactivate.json # PeopleController.deactivate with :id => 1
|
||||||
# GET /people/active.json # PeopleController.active
|
# GET /people/active.json # PeopleController.active
|
||||||
#
|
#
|
||||||
# Using this module, Active Resource can use these custom REST methods just like the
|
# Using this module, Active Resource can use these custom REST methods just like the
|
||||||
# standard methods.
|
# standard methods.
|
||||||
|
@ -63,6 +63,10 @@ module ActiveResource
|
||||||
connection.post(custom_method_collection_url(custom_method_name, options), body, headers)
|
connection.post(custom_method_collection_url(custom_method_name, options), body, headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def patch(custom_method_name, options = {}, body = '')
|
||||||
|
connection.patch(custom_method_collection_url(custom_method_name, options), body, headers)
|
||||||
|
end
|
||||||
|
|
||||||
def put(custom_method_name, options = {}, body = '')
|
def put(custom_method_name, options = {}, body = '')
|
||||||
connection.put(custom_method_collection_url(custom_method_name, options), body, headers)
|
connection.put(custom_method_collection_url(custom_method_name, options), body, headers)
|
||||||
end
|
end
|
||||||
|
@ -98,6 +102,10 @@ module ActiveResource
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def patch(method_name, options = {}, body = '')
|
||||||
|
connection.patch(custom_method_element_url(method_name, options), body, self.class.headers)
|
||||||
|
end
|
||||||
|
|
||||||
def put(method_name, options = {}, body = '')
|
def put(method_name, options = {}, body = '')
|
||||||
connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
|
connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@ module ActiveResource
|
||||||
#
|
#
|
||||||
# mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
# mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
||||||
#
|
#
|
||||||
# * <tt>http_method</tt> - The HTTP method to listen for. This can be +get+, +post+, +put+, +delete+ or
|
# * <tt>http_method</tt> - The HTTP method to listen for. This can be +get+, +post+, +patch+, +put+, +delete+ or
|
||||||
# +head+.
|
# +head+.
|
||||||
# * <tt>path</tt> - A string, starting with a "/", defining the URI that is expected to be
|
# * <tt>path</tt> - A string, starting with a "/", defining the URI that is expected to be
|
||||||
# called.
|
# called.
|
||||||
|
@ -55,7 +55,7 @@ module ActiveResource
|
||||||
@responses = responses
|
@responses = responses
|
||||||
end
|
end
|
||||||
|
|
||||||
[ :post, :put, :get, :delete, :head ].each do |method|
|
[ :post, :put, :patch, :get, :delete, :head ].each do |method|
|
||||||
# def post(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
# def post(path, request_headers = {}, body = nil, status = 200, response_headers = {})
|
||||||
# @responses[Request.new(:post, path, nil, request_headers)] = Response.new(body || "", status, response_headers)
|
# @responses[Request.new(:post, path, nil, request_headers)] = Response.new(body || "", status, response_headers)
|
||||||
# end
|
# end
|
||||||
|
@ -217,7 +217,7 @@ module ActiveResource
|
||||||
end
|
end
|
||||||
|
|
||||||
# body? methods
|
# body? methods
|
||||||
{ true => %w(post put),
|
{ true => %w(post patch put),
|
||||||
false => %w(get delete head) }.each do |has_body, methods|
|
false => %w(get delete head) }.each do |has_body, methods|
|
||||||
methods.each do |method|
|
methods.each do |method|
|
||||||
# def post(path, body, headers)
|
# def post(path, body, headers)
|
||||||
|
|
|
@ -11,11 +11,15 @@ class FormatTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_http_format_header_name
|
def test_http_format_header_name
|
||||||
header_name = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:get]
|
[:get, :head].each do |verb|
|
||||||
assert_equal 'Accept', header_name
|
header_name = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[verb]
|
||||||
|
assert_equal 'Accept', header_name
|
||||||
|
end
|
||||||
|
|
||||||
headers_names = [ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:put], ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:post]]
|
[:patch, :put, :post].each do |verb|
|
||||||
headers_names.each{ |name| assert_equal 'Content-Type', name }
|
header_name = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[verb]
|
||||||
|
assert_equal 'Content-Type', header_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_formats_on_single_element
|
def test_formats_on_single_element
|
||||||
|
|
|
@ -8,7 +8,7 @@ class HttpMockTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
FORMAT_HEADER = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES
|
FORMAT_HEADER = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES
|
||||||
|
|
||||||
[:post, :put, :get, :delete, :head].each do |method|
|
[:post, :patch, :put, :get, :delete, :head].each do |method|
|
||||||
test "responds to simple #{method} request" do
|
test "responds to simple #{method} request" do
|
||||||
ActiveResource::HttpMock.respond_to do |mock|
|
ActiveResource::HttpMock.respond_to do |mock|
|
||||||
mock.send(method, "/people/1", { FORMAT_HEADER[method] => "application/json" }, "Response")
|
mock.send(method, "/people/1", { FORMAT_HEADER[method] => "application/json" }, "Response")
|
||||||
|
@ -193,7 +193,7 @@ class HttpMockTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def request(method, path, headers = {}, body = nil)
|
def request(method, path, headers = {}, body = nil)
|
||||||
if method.in?([:put, :post])
|
if method.in?([:patch, :put, :post])
|
||||||
@http.send(method, path, body, headers)
|
@http.send(method, path, body, headers)
|
||||||
else
|
else
|
||||||
@http.send(method, path, headers)
|
@http.send(method, path, headers)
|
||||||
|
|
|
@ -563,7 +563,7 @@ The request object contains a lot of useful information about the request coming
|
||||||
|domain(n=2)|The hostname's first +n+ segments, starting from the right (the TLD).|
|
|domain(n=2)|The hostname's first +n+ segments, starting from the right (the TLD).|
|
||||||
|format|The content type requested by the client.|
|
|format|The content type requested by the client.|
|
||||||
|method|The HTTP method used for the request.|
|
|method|The HTTP method used for the request.|
|
||||||
|get?, post?, put?, delete?, head?|Returns true if the HTTP method is GET/POST/PUT/DELETE/HEAD.|
|
|get?, post?, patch?, put?, delete?, head?|Returns true if the HTTP method is GET/POST/PATCH/PUT/DELETE/HEAD.|
|
||||||
|headers|Returns a hash containing the headers associated with the request.|
|
|headers|Returns a hash containing the headers associated with the request.|
|
||||||
|port|The port number (integer) used for the request.|
|
|port|The port number (integer) used for the request.|
|
||||||
|protocol|Returns a string containing the protocol used plus "://", for example "http://".|
|
|protocol|Returns a string containing the protocol used plus "://", for example "http://".|
|
||||||
|
|
|
@ -146,7 +146,8 @@ link_to_remote "Add new item",
|
||||||
:position => :bottom
|
:position => :bottom
|
||||||
</ruby>
|
</ruby>
|
||||||
|
|
||||||
** *:method* Most typically you want to use a POST request when adding a remote link to your view so this is the default behavior. However, sometimes you'll want to update (PUT) or delete/destroy (DELETE) something and you can specify this with the +:method+ option. Let's see an example for a typical AJAX link for deleting an item from a list:
|
** *:method* Most typically you want to use a POST request when adding a remote
|
||||||
|
link to your view so this is the default behavior. However, sometimes you'll want to update (PUT/PATCH) or delete/destroy (DELETE) something and you can specify this with the +:method+ option. Let's see an example for a typical AJAX link for deleting an item from a list:
|
||||||
|
|
||||||
<ruby>
|
<ruby>
|
||||||
link_to_remote "Delete the item",
|
link_to_remote "Delete the item",
|
||||||
|
|
|
@ -76,6 +76,8 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is
|
||||||
|
|
||||||
* +config.consider_all_requests_local+ is a flag. If true then any error will cause detailed debugging information to be dumped in the HTTP response, and the +Rails::Info+ controller will show the application runtime context in +/rails/info/properties+. True by default in development and test environments, and false in production mode. For finer-grained control, set this to false and implement +local_request?+ in controllers to specify which requests should provide debugging information on errors.
|
* +config.consider_all_requests_local+ is a flag. If true then any error will cause detailed debugging information to be dumped in the HTTP response, and the +Rails::Info+ controller will show the application runtime context in +/rails/info/properties+. True by default in development and test environments, and false in production mode. For finer-grained control, set this to false and implement +local_request?+ in controllers to specify which requests should provide debugging information on errors.
|
||||||
|
|
||||||
|
* +config.default_method_for_update+ tells Rails which HTTP method to use for update actions by default. Set this to +:patch+ for proper HTTP update semantics. The default is +:put+ for backwards compatibility.
|
||||||
|
|
||||||
* +config.dependency_loading+ is a flag that allows you to disable constant autoloading setting it to false. It only has effect if +config.cache_classes+ is true, which it is by default in production mode. This flag is set to false by +config.threadsafe!+.
|
* +config.dependency_loading+ is a flag that allows you to disable constant autoloading setting it to false. It only has effect if +config.cache_classes+ is true, which it is by default in production mode. This flag is set to false by +config.threadsafe!+.
|
||||||
|
|
||||||
* +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the +app+ directory of the application.
|
* +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the +app+ directory of the application.
|
||||||
|
@ -214,7 +216,7 @@ Every Rails application comes with a standard set of middleware which it uses in
|
||||||
* +ActionDispatch::Session::CookieStore+ is responsible for storing the session in cookies. An alternate middleware can be used for this by changing the +config.action_controller.session_store+ to an alternate value. Additionally, options passed to this can be configured by using +config.action_controller.session_options+.
|
* +ActionDispatch::Session::CookieStore+ is responsible for storing the session in cookies. An alternate middleware can be used for this by changing the +config.action_controller.session_store+ to an alternate value. Additionally, options passed to this can be configured by using +config.action_controller.session_options+.
|
||||||
* +ActionDispatch::Flash+ sets up the +flash+ keys. Only available if +config.action_controller.session_store+ is set to a value.
|
* +ActionDispatch::Flash+ sets up the +flash+ keys. Only available if +config.action_controller.session_store+ is set to a value.
|
||||||
* +ActionDispatch::ParamsParser+ parses out parameters from the request into +params+.
|
* +ActionDispatch::ParamsParser+ parses out parameters from the request into +params+.
|
||||||
* +Rack::MethodOverride+ allows the method to be overridden if +params[:_method]+ is set. This is the middleware which supports the PUT and DELETE HTTP method types.
|
* +Rack::MethodOverride+ allows the method to be overridden if +params[:_method]+ is set. This is the middleware which supports the PUT, PATCH, and DELETE HTTP method types.
|
||||||
* +ActionDispatch::Head+ converts HEAD requests to GET requests and serves them as so.
|
* +ActionDispatch::Head+ converts HEAD requests to GET requests and serves them as so.
|
||||||
* +ActionDispatch::BestStandardsSupport+ enables "best standards support" so that IE8 renders some elements correctly.
|
* +ActionDispatch::BestStandardsSupport+ enables "best standards support" so that IE8 renders some elements correctly.
|
||||||
|
|
||||||
|
@ -346,7 +348,8 @@ h4. Configuring Action Dispatch
|
||||||
|
|
||||||
h4. Configuring Action View
|
h4. Configuring Action View
|
||||||
|
|
||||||
There are only a few configuration options for Action View, starting with four on +ActionView::Base+:
|
There are only a few configuration options for Action View, starting with six on +ActionView::Base+:
|
||||||
|
|
||||||
|
|
||||||
* +config.action_view.field_error_proc+ provides an HTML generator for displaying errors that come from Active Record. The default is
|
* +config.action_view.field_error_proc+ provides an HTML generator for displaying errors that come from Active Record. The default is
|
||||||
|
|
||||||
|
|
|
@ -303,6 +303,11 @@ Rails will also automatically set the +class+ and +id+ of the form appropriately
|
||||||
|
|
||||||
WARNING: When you're using STI (single-table inheritance) with your models, you can't rely on record identification on a subclass if only their parent class is declared a resource. You will have to specify the model name, +:url+, and +:method+ explicitly.
|
WARNING: When you're using STI (single-table inheritance) with your models, you can't rely on record identification on a subclass if only their parent class is declared a resource. You will have to specify the model name, +:url+, and +:method+ explicitly.
|
||||||
|
|
||||||
|
NOTE: Rails can use the +PATCH+ method instead of +PUT+ for update forms if you set the following option in your +config/application.rb+:
|
||||||
|
<ruby>
|
||||||
|
config.default_method_for_update = :patch
|
||||||
|
</ruby>
|
||||||
|
|
||||||
h5. Dealing with Namespaces
|
h5. Dealing with Namespaces
|
||||||
|
|
||||||
If you have created namespaced routes, +form_for+ has a nifty shorthand for that too. If your application has an admin namespace then
|
If you have created namespaced routes, +form_for+ has a nifty shorthand for that too. If your application has an admin namespace then
|
||||||
|
@ -320,14 +325,14 @@ form_for [:admin, :management, @article]
|
||||||
For more information on Rails' routing system and the associated conventions, please see the "routing guide":routing.html.
|
For more information on Rails' routing system and the associated conventions, please see the "routing guide":routing.html.
|
||||||
|
|
||||||
|
|
||||||
h4. How do forms with PUT or DELETE methods work?
|
h4. How do forms with PATCH, PUT, or DELETE methods work?
|
||||||
|
|
||||||
The Rails framework encourages RESTful design of your applications, which means you'll be making a lot of "PUT" and "DELETE" requests (besides "GET" and "POST"). However, most browsers _don't support_ methods other than "GET" and "POST" when it comes to submitting forms.
|
The Rails framework encourages RESTful design of your applications, which means you'll be making a lot of "PATCH" and "DELETE" requests (besides "GET" and "POST"). However, most browsers _don't support_ methods other than "GET" and "POST" when it comes to submitting forms.
|
||||||
|
|
||||||
Rails works around this issue by emulating other methods over POST with a hidden input named +"_method"+, which is set to reflect the desired method:
|
Rails works around this issue by emulating other methods over POST with a hidden input named +"_method"+, which is set to reflect the desired method:
|
||||||
|
|
||||||
<ruby>
|
<ruby>
|
||||||
form_tag(search_path, :method => "put")
|
form_tag(search_path, :method => "patch")
|
||||||
</ruby>
|
</ruby>
|
||||||
|
|
||||||
output:
|
output:
|
||||||
|
@ -335,14 +340,14 @@ output:
|
||||||
<html>
|
<html>
|
||||||
<form accept-charset="UTF-8" action="/search" method="post">
|
<form accept-charset="UTF-8" action="/search" method="post">
|
||||||
<div style="margin:0;padding:0">
|
<div style="margin:0;padding:0">
|
||||||
<input name="_method" type="hidden" value="put" />
|
<input name="_method" type="hidden" value="patch" />
|
||||||
<input name="utf8" type="hidden" value="✓" />
|
<input name="utf8" type="hidden" value="✓" />
|
||||||
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
|
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
|
||||||
</div>
|
</div>
|
||||||
...
|
...
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
When parsing POSTed data, Rails will take into account the special +_method+ parameter and acts as if the HTTP method was the one specified inside it ("PUT" in this example).
|
When parsing POSTed data, Rails will take into account the special +_method+ parameter and acts as if the HTTP method was the one specified inside it ("PATCH" in this example).
|
||||||
|
|
||||||
h3. Making Select Boxes with Ease
|
h3. Making Select Boxes with Ease
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ Resource routing allows you to quickly declare all of the common routes for a gi
|
||||||
|
|
||||||
h4. Resources on the Web
|
h4. Resources on the Web
|
||||||
|
|
||||||
Browsers request pages from Rails by making a request for a URL using a specific HTTP method, such as +GET+, +POST+, +PUT+ and +DELETE+. Each method is a request to perform an operation on the resource. A resource route maps a number of related requests to actions in a single controller.
|
Browsers request pages from Rails by making a request for a URL using a specific HTTP method, such as +GET+, +POST+, +PATCH+, +PUT+ and +DELETE+. Each method is a request to perform an operation on the resource. A resource route maps a number of related requests to actions in a single controller.
|
||||||
|
|
||||||
When your Rails application receives an incoming request for
|
When your Rails application receives an incoming request for
|
||||||
|
|
||||||
|
@ -82,11 +82,10 @@ creates seven different routes in your application, all mapping to the +Photos+
|
||||||
|POST |/photos |create |create a new photo |
|
|POST |/photos |create |create a new photo |
|
||||||
|GET |/photos/:id |show |display a specific photo |
|
|GET |/photos/:id |show |display a specific photo |
|
||||||
|GET |/photos/:id/edit |edit |return an HTML form for editing a photo |
|
|GET |/photos/:id/edit |edit |return an HTML form for editing a photo |
|
||||||
|PUT |/photos/:id |update |update a specific photo |
|
|PUT/PATCH |/photos/:id |update |update a specific photo |
|
||||||
|DELETE |/photos/:id |destroy |delete a specific photo |
|
|DELETE |/photos/:id |destroy |delete a specific photo |
|
||||||
|
|
||||||
|
NOTE: The HTTP Verb for the +update+ action defaults to +PUT+ for backwards compatibility. Set +config.default_method_for_update+ to +:patch+ to use +PATCH+. Rails routes are matched in the order they are specified, so if you have a +resources :photos+ above a +get 'photos/poll'+ the +show+ action's route for the +resources+ line will be matched before the +get+ line. To fix this, move the +get+ line *above* the +resources+ line so that it is matched first.
|
||||||
NOTE: Rails routes are matched in the order they are specified, so if you have a +resources :photos+ above a +get 'photos/poll'+ the +show+ action's route for the +resources+ line will be matched before the +get+ line. To fix this, move the +get+ line *above* the +resources+ line so that it is matched first.
|
|
||||||
|
|
||||||
h4. Paths and URLs
|
h4. Paths and URLs
|
||||||
|
|
||||||
|
@ -138,10 +137,10 @@ creates six different routes in your application, all mapping to the +Geocoders+
|
||||||
|POST |/geocoder |create |create the new geocoder |
|
|POST |/geocoder |create |create the new geocoder |
|
||||||
|GET |/geocoder |show |display the one and only geocoder resource |
|
|GET |/geocoder |show |display the one and only geocoder resource |
|
||||||
|GET |/geocoder/edit |edit |return an HTML form for editing the geocoder |
|
|GET |/geocoder/edit |edit |return an HTML form for editing the geocoder |
|
||||||
|PUT |/geocoder |update |update the one and only geocoder resource |
|
|PUT/PATCH |/geocoder |update |update the one and only geocoder resource |
|
||||||
|DELETE |/geocoder |destroy |delete the geocoder resource |
|
|DELETE |/geocoder |destroy |delete the geocoder resource |
|
||||||
|
|
||||||
NOTE: Because you might want to use the same controller for a singular route (+/account+) and a plural route (+/accounts/45+), singular resources map to plural controllers.
|
NOTE: The HTTP Verb for the +update+ action defaults to +PUT+ for backwards compatibility. Set +config.default_method_for_update+ to +:patch+ to use +PATCH+. Because you might want to use the same controller for a singular route (+/account+) and a plural route (+/accounts/45+), singular resources map to plural controllers.
|
||||||
|
|
||||||
A singular resourceful route generates these helpers:
|
A singular resourceful route generates these helpers:
|
||||||
|
|
||||||
|
@ -169,9 +168,11 @@ This will create a number of routes for each of the +posts+ and +comments+ contr
|
||||||
|POST |/admin/posts |create | admin_posts_path |
|
|POST |/admin/posts |create | admin_posts_path |
|
||||||
|GET |/admin/posts/:id |show | admin_post_path(:id) |
|
|GET |/admin/posts/:id |show | admin_post_path(:id) |
|
||||||
|GET |/admin/posts/:id/edit |edit | edit_admin_post_path(:id) |
|
|GET |/admin/posts/:id/edit |edit | edit_admin_post_path(:id) |
|
||||||
|PUT |/admin/posts/:id |update | admin_post_path(:id) |
|
|PUT/PATCH |/admin/posts/:id |update | admin_post_path(:id) |
|
||||||
|DELETE |/admin/posts/:id |destroy | admin_post_path(:id) |
|
|DELETE |/admin/posts/:id |destroy | admin_post_path(:id) |
|
||||||
|
|
||||||
|
NOTE: The HTTP Verb for the +update+ action defaults to +PUT+ for backwards compatibility. Set +config.default_method_for_update+ to +:patch+ to use +PATCH+.
|
||||||
|
|
||||||
If you want to route +/posts+ (without the prefix +/admin+) to +Admin::PostsController+, you could use
|
If you want to route +/posts+ (without the prefix +/admin+) to +Admin::PostsController+, you could use
|
||||||
|
|
||||||
<ruby>
|
<ruby>
|
||||||
|
@ -208,9 +209,11 @@ In each of these cases, the named routes remain the same as if you did not use +
|
||||||
|POST |/admin/posts |create | posts_path |
|
|POST |/admin/posts |create | posts_path |
|
||||||
|GET |/admin/posts/:id |show | post_path(:id) |
|
|GET |/admin/posts/:id |show | post_path(:id) |
|
||||||
|GET |/admin/posts/:id/edit|edit | edit_post_path(:id)|
|
|GET |/admin/posts/:id/edit|edit | edit_post_path(:id)|
|
||||||
|PUT |/admin/posts/:id |update | post_path(:id) |
|
|PUT/PATCH |/admin/posts/:id |update | post_path(:id) |
|
||||||
|DELETE |/admin/posts/:id |destroy | post_path(:id) |
|
|DELETE |/admin/posts/:id |destroy | post_path(:id) |
|
||||||
|
|
||||||
|
NOTE: The HTTP Verb for the +update+ action defaults to +PUT+ for backwards compatibility. Set +config.default_method_for_update+ to +:patch+ to use +PATCH+.
|
||||||
|
|
||||||
h4. Nested Resources
|
h4. Nested Resources
|
||||||
|
|
||||||
It's common to have resources that are logically children of other resources. For example, suppose your application includes these models:
|
It's common to have resources that are logically children of other resources. For example, suppose your application includes these models:
|
||||||
|
@ -235,15 +238,16 @@ end
|
||||||
|
|
||||||
In addition to the routes for magazines, this declaration will also route ads to an +AdsController+. The ad URLs require a magazine:
|
In addition to the routes for magazines, this declaration will also route ads to an +AdsController+. The ad URLs require a magazine:
|
||||||
|
|
||||||
|_.HTTP Verb |_.Path |_.action |_.used for |
|
|_.HTTP Verb |_.Path |_.action |_.used for |
|
||||||
|GET |/magazines/:id/ads |index |display a list of all ads for a specific magazine |
|
|GET |/magazines/:id/ads |index |display a list of all ads for a specific magazine |
|
||||||
|GET |/magazines/:id/ads/new |new |return an HTML form for creating a new ad belonging to a specific magazine |
|
|GET |/magazines/:id/ads/new |new |return an HTML form for creating a new ad belonging to a specific magazine |
|
||||||
|POST |/magazines/:id/ads |create |create a new ad belonging to a specific magazine |
|
|POST |/magazines/:id/ads |create |create a new ad belonging to a specific magazine |
|
||||||
|GET |/magazines/:id/ads/:id |show |display a specific ad belonging to a specific magazine |
|
|GET |/magazines/:id/ads/:id |show |display a specific ad belonging to a specific magazine |
|
||||||
|GET |/magazines/:id/ads/:id/edit |edit |return an HTML form for editing an ad belonging to a specific magazine |
|
|GET |/magazines/:id/ads/:id/edit |edit |return an HTML form for editing an ad belonging to a specific magazine |
|
||||||
|PUT |/magazines/:id/ads/:id |update |update a specific ad belonging to a specific magazine |
|
|PUT/PATCH |/magazines/:id/ads/:id |update |update a specific ad belonging to a specific magazine |
|
||||||
|DELETE |/magazines/:id/ads/:id |destroy |delete a specific ad belonging to a specific magazine |
|
|DELETE |/magazines/:id/ads/:id |destroy |delete a specific ad belonging to a specific magazine |
|
||||||
|
|
||||||
|
NOTE: The HTTP Verb for the +update+ action defaults to +PUT+ for backwards compatibility. Set +config.default_method_for_update+ to +:patch+ to use +PATCH+.
|
||||||
|
|
||||||
This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+. These helpers take an instance of Magazine as the first parameter (+magazine_ads_url(@magazine)+).
|
This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+. These helpers take an instance of Magazine as the first parameter (+magazine_ads_url(@magazine)+).
|
||||||
|
|
||||||
|
@ -323,7 +327,7 @@ end
|
||||||
|
|
||||||
This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers.
|
This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers.
|
||||||
|
|
||||||
Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, or +delete+ here. If you don't have multiple +member+ routes, you can also pass +:on+ to a route, eliminating the block:
|
Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +patch+, +put+, +post+, or +delete+ here. If you don't have multiple +member+ routes, you can also pass +:on+ to a route, eliminating the block:
|
||||||
|
|
||||||
<ruby>
|
<ruby>
|
||||||
resources :photos do
|
resources :photos do
|
||||||
|
@ -642,7 +646,7 @@ will recognize incoming paths beginning with +/photos+ but route to the +Images+
|
||||||
|POST |/photos |create | photos_path |
|
|POST |/photos |create | photos_path |
|
||||||
|GET |/photos/:id |show | photo_path(:id) |
|
|GET |/photos/:id |show | photo_path(:id) |
|
||||||
|GET |/photos/:id/edit |edit | edit_photo_path(:id) |
|
|GET |/photos/:id/edit |edit | edit_photo_path(:id) |
|
||||||
|PUT |/photos/:id |update | photo_path(:id) |
|
|PUT/PATCH |/photos/:id |update | photo_path(:id) |
|
||||||
|DELETE |/photos/:id |destroy | photo_path(:id) |
|
|DELETE |/photos/:id |destroy | photo_path(:id) |
|
||||||
|
|
||||||
NOTE: Use +photos_path+, +new_photo_path+, etc. to generate paths for this resource.
|
NOTE: Use +photos_path+, +new_photo_path+, etc. to generate paths for this resource.
|
||||||
|
@ -686,9 +690,11 @@ will recognize incoming paths beginning with +/photos+ and route the requests to
|
||||||
|POST |/photos |create | images_path |
|
|POST |/photos |create | images_path |
|
||||||
|GET |/photos/:id |show | image_path(:id) |
|
|GET |/photos/:id |show | image_path(:id) |
|
||||||
|GET |/photos/:id/edit |edit | edit_image_path(:id) |
|
|GET |/photos/:id/edit |edit | edit_image_path(:id) |
|
||||||
|PUT |/photos/:id |update | image_path(:id) |
|
|PUT/PATCH |/photos/:id |update | image_path(:id) |
|
||||||
|DELETE |/photos/:id |destroy | image_path(:id) |
|
|DELETE |/photos/:id |destroy | image_path(:id) |
|
||||||
|
|
||||||
|
NOTE: The HTTP Verb for the +update+ action defaults to +PUT+ for backwards compatibility. Set +config.default_method_for_update+ to +:patch+ to use +PATCH+.
|
||||||
|
|
||||||
h4. Overriding the +new+ and +edit+ Segments
|
h4. Overriding the +new+ and +edit+ Segments
|
||||||
|
|
||||||
The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in paths:
|
The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in paths:
|
||||||
|
@ -790,9 +796,11 @@ Rails now creates routes to the +CategoriesController+.
|
||||||
|POST |/kategorien |create | categories_path |
|
|POST |/kategorien |create | categories_path |
|
||||||
|GET |/kategorien/:id |show | category_path(:id) |
|
|GET |/kategorien/:id |show | category_path(:id) |
|
||||||
|GET |/kategorien/:id/bearbeiten |edit | edit_category_path(:id) |
|
|GET |/kategorien/:id/bearbeiten |edit | edit_category_path(:id) |
|
||||||
|PUT |/kategorien/:id |update | category_path(:id) |
|
|PUT/PATCH |/kategorien/:id |update | category_path(:id) |
|
||||||
|DELETE |/kategorien/:id |destroy | category_path(:id) |
|
|DELETE |/kategorien/:id |destroy | category_path(:id) |
|
||||||
|
|
||||||
|
NOTE: The HTTP Verb for the +update+ action defaults to +PUT+ for backwards compatibility. Set +config.default_method_for_update+ to +:patch+ to use +PATCH+.
|
||||||
|
|
||||||
h4. Overriding the Singular Form
|
h4. Overriding the Singular Form
|
||||||
|
|
||||||
If you want to define the singular form of a resource, you should add additional rules to the +Inflector+.
|
If you want to define the singular form of a resource, you should add additional rules to the +Inflector+.
|
||||||
|
|
|
@ -483,10 +483,11 @@ Now you can try running all the tests and they should pass.
|
||||||
|
|
||||||
h4. Available Request Types for Functional Tests
|
h4. Available Request Types for Functional Tests
|
||||||
|
|
||||||
If you're familiar with the HTTP protocol, you'll know that +get+ is a type of request. There are 5 request types supported in Rails functional tests:
|
If you're familiar with the HTTP protocol, you'll know that +get+ is a type of request. There are 6 request types supported in Rails functional tests:
|
||||||
|
|
||||||
* +get+
|
* +get+
|
||||||
* +post+
|
* +post+
|
||||||
|
* +patch+
|
||||||
* +put+
|
* +put+
|
||||||
* +head+
|
* +head+
|
||||||
* +delete+
|
* +delete+
|
||||||
|
@ -638,6 +639,7 @@ In addition to the standard testing helpers, there are some additional helpers a
|
||||||
|+request_via_redirect(http_method, path, [parameters], [headers])+ |Allows you to make an HTTP request and follow any subsequent redirects.|
|
|+request_via_redirect(http_method, path, [parameters], [headers])+ |Allows you to make an HTTP request and follow any subsequent redirects.|
|
||||||
|+post_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP POST request and follow any subsequent redirects.|
|
|+post_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP POST request and follow any subsequent redirects.|
|
||||||
|+get_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP GET request and follow any subsequent redirects.|
|
|+get_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP GET request and follow any subsequent redirects.|
|
||||||
|
|+patch_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP PATCH request and follow any subsequent redirects.|
|
||||||
|+put_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP PUT request and follow any subsequent redirects.|
|
|+put_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP PUT request and follow any subsequent redirects.|
|
||||||
|+delete_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP DELETE request and follow any subsequent redirects.|
|
|+delete_via_redirect(path, [parameters], [headers])+ |Allows you to make an HTTP DELETE request and follow any subsequent redirects.|
|
||||||
|+open_session+ |Opens a new session instance.|
|
|+open_session+ |Opens a new session instance.|
|
||||||
|
@ -810,7 +812,7 @@ class PostsControllerTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should update post" do
|
test "should update post" do
|
||||||
put :update, :id => @post.id, :post => { }
|
patch :update, :id => @post.id, :post => { }
|
||||||
assert_redirected_to post_path(assigns(:post))
|
assert_redirected_to post_path(assigns(:post))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ module Rails
|
||||||
:force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks,
|
:force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks,
|
||||||
:railties_order, :relative_url_root, :secret_token,
|
:railties_order, :relative_url_root, :secret_token,
|
||||||
:serve_static_assets, :ssl_options, :static_cache_control, :session_options,
|
:serve_static_assets, :ssl_options, :static_cache_control, :session_options,
|
||||||
:time_zone, :reload_classes_only_on_change
|
:time_zone, :reload_classes_only_on_change, :default_method_for_update
|
||||||
|
|
||||||
attr_writer :log_level
|
attr_writer :log_level
|
||||||
attr_reader :encoding
|
attr_reader :encoding
|
||||||
|
@ -40,6 +40,7 @@ module Rails
|
||||||
@reload_classes_only_on_change = true
|
@reload_classes_only_on_change = true
|
||||||
@file_watcher = ActiveSupport::FileUpdateChecker
|
@file_watcher = ActiveSupport::FileUpdateChecker
|
||||||
@exceptions_app = nil
|
@exceptions_app = nil
|
||||||
|
@default_method_for_update = :put
|
||||||
|
|
||||||
@assets = ActiveSupport::OrderedOptions.new
|
@assets = ActiveSupport::OrderedOptions.new
|
||||||
@assets.enabled = false
|
@assets.enabled = false
|
||||||
|
|
|
@ -37,7 +37,7 @@ module Rails
|
||||||
|
|
||||||
# GET show
|
# GET show
|
||||||
# GET edit
|
# GET edit
|
||||||
# PUT update
|
# PUT/PATCH update
|
||||||
# DELETE destroy
|
# DELETE destroy
|
||||||
def self.find(klass, params=nil)
|
def self.find(klass, params=nil)
|
||||||
"#{klass}.find(#{params})"
|
"#{klass}.find(#{params})"
|
||||||
|
@ -58,13 +58,13 @@ module Rails
|
||||||
"#{name}.save"
|
"#{name}.save"
|
||||||
end
|
end
|
||||||
|
|
||||||
# PUT update
|
# PUT/PATCH update
|
||||||
def update_attributes(params=nil)
|
def update_attributes(params=nil)
|
||||||
"#{name}.update_attributes(#{params})"
|
"#{name}.update_attributes(#{params})"
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST create
|
# POST create
|
||||||
# PUT update
|
# PUT/PATCH update
|
||||||
def errors
|
def errors
|
||||||
"#{name}.errors"
|
"#{name}.errors"
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,6 +31,9 @@ module <%= app_const_base %>
|
||||||
# Activate observers that should always be running.
|
# Activate observers that should always be running.
|
||||||
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
||||||
|
|
||||||
|
# Use PATCH as default method for update actions
|
||||||
|
# config.default_method_for_update = :patch
|
||||||
|
|
||||||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||||
# config.time_zone = 'Central Time (US & Canada)'
|
# config.time_zone = 'Central Time (US & Canada)'
|
||||||
|
|
|
@ -54,8 +54,8 @@ class <%= controller_class_name %>Controller < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# PUT <%= route_url %>/1
|
# PUT/PATCH <%= route_url %>/1
|
||||||
# PUT <%= route_url %>/1.json
|
# PUT/PATCH <%= route_url %>/1.json
|
||||||
def update
|
def update
|
||||||
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ module ApplicationTests
|
||||||
test "frameworks are not preloaded by default" do
|
test "frameworks are not preloaded by default" do
|
||||||
require "#{app_path}/config/environment"
|
require "#{app_path}/config/environment"
|
||||||
|
|
||||||
assert ActionController.autoload?(:RecordIdentifier)
|
assert ActionController.autoload?(:Caching)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "frameworks are preloaded with config.preload_frameworks is set" do
|
test "frameworks are preloaded with config.preload_frameworks is set" do
|
||||||
|
@ -156,7 +156,7 @@ module ApplicationTests
|
||||||
|
|
||||||
require "#{app_path}/config/environment"
|
require "#{app_path}/config/environment"
|
||||||
|
|
||||||
assert !ActionController.autoload?(:RecordIdentifier)
|
assert !ActionController.autoload?(:Caching)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "filter_parameters should be able to set via config.filter_parameters" do
|
test "filter_parameters should be able to set via config.filter_parameters" do
|
||||||
|
@ -246,6 +246,49 @@ module ApplicationTests
|
||||||
assert last_response.body =~ /csrf\-param/
|
assert last_response.body =~ /csrf\-param/
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "default method for update can be changed" do
|
||||||
|
app_file 'app/models/post.rb', <<-RUBY
|
||||||
|
class Post
|
||||||
|
extend ActiveModel::Naming
|
||||||
|
def to_key; [1]; end
|
||||||
|
def persisted?; true; end
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
app_file 'app/controllers/posts_controller.rb', <<-RUBY
|
||||||
|
class PostsController < ApplicationController
|
||||||
|
def show
|
||||||
|
render :inline => "<%= begin; form_for(Post.new) {}; rescue => e; e.to_s; end %>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
render :text => "update"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
add_to_config <<-RUBY
|
||||||
|
config.default_method_for_update = :patch
|
||||||
|
routes.prepend do
|
||||||
|
resources :posts
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
require "#{app_path}/config/environment"
|
||||||
|
|
||||||
|
assert_equal ActionView::Base.default_method_for_update, :patch
|
||||||
|
assert_equal ActionDispatch::Routing::Mapper.default_method_for_update, :patch
|
||||||
|
|
||||||
|
get "/posts/1"
|
||||||
|
assert_match /patch/, last_response.body
|
||||||
|
|
||||||
|
patch "/posts/1"
|
||||||
|
assert_match /update/, last_response.body
|
||||||
|
|
||||||
|
put "/posts/1"
|
||||||
|
assert_equal 404, last_response.status
|
||||||
|
end
|
||||||
|
|
||||||
test "request forgery token param can be changed" do
|
test "request forgery token param can be changed" do
|
||||||
make_basic_app do
|
make_basic_app do
|
||||||
app.config.action_controller.request_forgery_protection_token = '_xsrf_token_here'
|
app.config.action_controller.request_forgery_protection_token = '_xsrf_token_here'
|
||||||
|
|
|
@ -325,6 +325,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
|
||||||
assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/
|
assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_default_method_for_update_is_not_patch
|
||||||
|
run_generator [destination_root, "--skip-test-unit", "--skip-active-record"]
|
||||||
|
assert_file "config/application.rb", /#\s+config\.default_method_for_update\s+=\s+:patch/
|
||||||
|
end
|
||||||
|
|
||||||
def test_new_hash_style
|
def test_new_hash_style
|
||||||
run_generator [destination_root]
|
run_generator [destination_root]
|
||||||
assert_file "config/initializers/session_store.rb" do |file|
|
assert_file "config/initializers/session_store.rb" do |file|
|
||||||
|
|
Loading…
Reference in a new issue