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'
|
||||
end
|
||||
|
||||
gem 'rack-test', :git => "https://github.com/brynary/rack-test.git"
|
||||
gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
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
|
||||
# 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.
|
||||
#
|
||||
# The nonce is opaque to the client. Composed of Time, and hash of Time with secret
|
||||
|
@ -293,7 +293,7 @@ module ActionController
|
|||
end
|
||||
|
||||
# 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
|
||||
# allow a user to use new nonce without prompting user again for their
|
||||
# username and password.
|
||||
|
|
|
@ -53,7 +53,7 @@ module ActionController #:nodoc:
|
|||
# end
|
||||
# end
|
||||
#
|
||||
# The same happens for PUT and DELETE requests.
|
||||
# The same happens for PATCH/PUT and DELETE requests.
|
||||
#
|
||||
# === Nested resources
|
||||
#
|
||||
|
@ -116,8 +116,9 @@ module ActionController #:nodoc:
|
|||
class Responder
|
||||
attr_reader :controller, :request, :format, :resource, :resources, :options
|
||||
|
||||
ACTIONS_FOR_VERBS = {
|
||||
DEFAULT_ACTIONS_FOR_VERBS = {
|
||||
:post => :new,
|
||||
:patch => :edit,
|
||||
:put => :edit
|
||||
}
|
||||
|
||||
|
@ -132,7 +133,7 @@ module ActionController #:nodoc:
|
|||
end
|
||||
|
||||
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
|
||||
undef_method(:to_json) if method_defined?(:to_json)
|
||||
|
@ -259,11 +260,11 @@ module ActionController #:nodoc:
|
|||
resource.respond_to?(:errors) && !resource.errors.empty?
|
||||
end
|
||||
|
||||
# By default, render the <code>:edit</code> action for HTML requests with failure, unless
|
||||
# the verb is POST.
|
||||
# By default, render the <code>:edit</code> action for HTML requests with errors, unless
|
||||
# the verb was POST.
|
||||
#
|
||||
def default_action
|
||||
@action ||= ACTIONS_FOR_VERBS[request.request_method_symbol]
|
||||
@action ||= DEFAULT_ACTIONS_FOR_VERBS[request.request_method_symbol]
|
||||
end
|
||||
|
||||
def resource_errors
|
||||
|
|
|
@ -225,7 +225,7 @@ module ActionController
|
|||
# == Basic example
|
||||
#
|
||||
# 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.
|
||||
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
||||
# the controller's HTTP response, the database contents, etc.
|
||||
|
@ -392,6 +392,11 @@ module ActionController
|
|||
process(action, "POST", *args)
|
||||
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
|
||||
def put(action, *args)
|
||||
process(action, "PUT", *args)
|
||||
|
|
|
@ -97,6 +97,12 @@ module ActionDispatch
|
|||
HTTP_METHOD_LOOKUP[request_method] == :post
|
||||
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?
|
||||
# Equivalent to <tt>request.request_method_symbol == :put</tt>.
|
||||
def put?
|
||||
|
|
|
@ -23,6 +23,7 @@ module ActionDispatch
|
|||
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
|
||||
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::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_templates.merge!(config.action_dispatch.rescue_templates)
|
||||
|
|
|
@ -182,10 +182,13 @@ module ActionDispatch
|
|||
#
|
||||
# == HTTP Methods
|
||||
#
|
||||
# Using the <tt>:via</tt> option when specifying a route allows you to restrict it to a specific HTTP method.
|
||||
# Possible values are <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <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.
|
||||
# Using the <tt>:via</tt> option when specifying a route allows you to
|
||||
# restrict it to a specific HTTP method. Possible values are <tt>:post</tt>,
|
||||
# <tt>:get</tt>, <tt>:patch</tt>, <tt>:put</tt>, <tt>:delete</tt> and
|
||||
# <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:
|
||||
#
|
||||
|
@ -198,7 +201,7 @@ module ActionDispatch
|
|||
# === HTTP helper methods
|
||||
#
|
||||
# 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:
|
||||
#
|
||||
|
@ -283,6 +286,6 @@ module ActionDispatch
|
|||
autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
|
||||
|
||||
SEPARATORS = %w( / . ? ) #:nodoc:
|
||||
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options] #:nodoc:
|
||||
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] #:nodoc:
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,6 +7,8 @@ require 'action_dispatch/routing/redirection'
|
|||
module ActionDispatch
|
||||
module Routing
|
||||
class Mapper
|
||||
cattr_accessor(:default_method_for_update) {:put}
|
||||
|
||||
class Constraints #:nodoc:
|
||||
def self.new(app, constraints, request = Rack::Request)
|
||||
if constraints.any?
|
||||
|
@ -465,7 +467,7 @@ module ActionDispatch
|
|||
#
|
||||
# Example:
|
||||
#
|
||||
# get 'bacon', :to => 'food#bacon'
|
||||
# get 'bacon', :to => 'food#bacon'
|
||||
def get(*args, &block)
|
||||
map_method(:get, args, &block)
|
||||
end
|
||||
|
@ -475,17 +477,27 @@ module ActionDispatch
|
|||
#
|
||||
# Example:
|
||||
#
|
||||
# post 'bacon', :to => 'food#bacon'
|
||||
# post 'bacon', :to => 'food#bacon'
|
||||
def post(*args, &block)
|
||||
map_method(:post, args, &block)
|
||||
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.
|
||||
# For supported arguments, see <tt>Base#match</tt>.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# put 'bacon', :to => 'food#bacon'
|
||||
# put 'bacon', :to => 'food#bacon'
|
||||
def put(*args, &block)
|
||||
map_method(:put, args, &block)
|
||||
end
|
||||
|
@ -495,7 +507,7 @@ module ActionDispatch
|
|||
#
|
||||
# Example:
|
||||
#
|
||||
# delete 'broccoli', :to => 'food#broccoli'
|
||||
# delete 'broccoli', :to => 'food#broccoli'
|
||||
def delete(*args, &block)
|
||||
map_method(:delete, args, &block)
|
||||
end
|
||||
|
@ -522,13 +534,13 @@ module ActionDispatch
|
|||
# This will create a number of routes for each of the posts and comments
|
||||
# controller. For <tt>Admin::PostsController</tt>, Rails will create:
|
||||
#
|
||||
# GET /admin/posts
|
||||
# GET /admin/posts/new
|
||||
# POST /admin/posts
|
||||
# GET /admin/posts/1
|
||||
# GET /admin/posts/1/edit
|
||||
# PUT /admin/posts/1
|
||||
# DELETE /admin/posts/1
|
||||
# GET /admin/posts
|
||||
# GET /admin/posts/new
|
||||
# POST /admin/posts
|
||||
# GET /admin/posts/1
|
||||
# GET /admin/posts/1/edit
|
||||
# PUT/PATCH /admin/posts/1
|
||||
# DELETE /admin/posts/1
|
||||
#
|
||||
# If you want to route /posts (without the prefix /admin) to
|
||||
# <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
|
||||
# +PostsController+:
|
||||
#
|
||||
# GET /admin/posts
|
||||
# GET /admin/posts/new
|
||||
# POST /admin/posts
|
||||
# GET /admin/posts/1
|
||||
# GET /admin/posts/1/edit
|
||||
# PUT /admin/posts/1
|
||||
# DELETE /admin/posts/1
|
||||
# GET /admin/posts
|
||||
# GET /admin/posts/new
|
||||
# POST /admin/posts
|
||||
# GET /admin/posts/1
|
||||
# GET /admin/posts/1/edit
|
||||
# PUT/PATCH /admin/posts/1
|
||||
# DELETE /admin/posts/1
|
||||
module Scoping
|
||||
# Scopes a set of routes to the given default options.
|
||||
#
|
||||
|
@ -651,13 +663,13 @@ module ActionDispatch
|
|||
#
|
||||
# This generates the following routes:
|
||||
#
|
||||
# admin_posts GET /admin/posts(.:format) admin/posts#index
|
||||
# admin_posts POST /admin/posts(.:format) admin/posts#create
|
||||
# new_admin_post GET /admin/posts/new(.:format) admin/posts#new
|
||||
# edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
|
||||
# admin_post GET /admin/posts/:id(.:format) admin/posts#show
|
||||
# admin_post PUT /admin/posts/:id(.:format) admin/posts#update
|
||||
# admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
|
||||
# admin_posts GET /admin/posts(.:format) admin/posts#index
|
||||
# admin_posts POST /admin/posts(.:format) admin/posts#create
|
||||
# new_admin_post GET /admin/posts/new(.:format) admin/posts#new
|
||||
# edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
|
||||
# admin_post GET /admin/posts/:id(.:format) admin/posts#show
|
||||
# admin_post PUT/PATCH /admin/posts/:id(.:format) admin/posts#update
|
||||
# admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
|
||||
#
|
||||
# === Options
|
||||
#
|
||||
|
@ -972,12 +984,12 @@ module ActionDispatch
|
|||
# the +GeoCoders+ controller (note that the controller is named after
|
||||
# the plural):
|
||||
#
|
||||
# GET /geocoder/new
|
||||
# POST /geocoder
|
||||
# GET /geocoder
|
||||
# GET /geocoder/edit
|
||||
# PUT /geocoder
|
||||
# DELETE /geocoder
|
||||
# GET /geocoder/new
|
||||
# POST /geocoder
|
||||
# GET /geocoder
|
||||
# GET /geocoder/edit
|
||||
# PUT/PATCH /geocoder
|
||||
# DELETE /geocoder
|
||||
#
|
||||
# === Options
|
||||
# Takes same options as +resources+.
|
||||
|
@ -1002,8 +1014,10 @@ module ActionDispatch
|
|||
member do
|
||||
get :edit if parent_resource.actions.include?(:edit)
|
||||
get :show if parent_resource.actions.include?(:show)
|
||||
put :update if parent_resource.actions.include?(:update)
|
||||
delete :destroy if parent_resource.actions.include?(:destroy)
|
||||
if parent_resource.actions.include?(:update)
|
||||
send default_method_for_update, :update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1020,13 +1034,13 @@ module ActionDispatch
|
|||
# creates seven different routes in your application, all mapping to
|
||||
# the +Photos+ controller:
|
||||
#
|
||||
# GET /photos
|
||||
# GET /photos/new
|
||||
# POST /photos
|
||||
# GET /photos/:id
|
||||
# GET /photos/:id/edit
|
||||
# PUT /photos/:id
|
||||
# DELETE /photos/:id
|
||||
# GET /photos
|
||||
# GET /photos/new
|
||||
# POST /photos
|
||||
# GET /photos/:id
|
||||
# GET /photos/:id/edit
|
||||
# PUT/PATCH /photos/:id
|
||||
# DELETE /photos/:id
|
||||
#
|
||||
# Resources can also be nested infinitely by using this block syntax:
|
||||
#
|
||||
|
@ -1036,13 +1050,13 @@ module ActionDispatch
|
|||
#
|
||||
# This generates the following comments routes:
|
||||
#
|
||||
# GET /photos/:photo_id/comments
|
||||
# GET /photos/:photo_id/comments/new
|
||||
# POST /photos/:photo_id/comments
|
||||
# GET /photos/:photo_id/comments/:id
|
||||
# GET /photos/:photo_id/comments/:id/edit
|
||||
# PUT /photos/:photo_id/comments/:id
|
||||
# DELETE /photos/:photo_id/comments/:id
|
||||
# GET /photos/:photo_id/comments
|
||||
# GET /photos/:photo_id/comments/new
|
||||
# POST /photos/:photo_id/comments
|
||||
# GET /photos/:photo_id/comments/:id
|
||||
# GET /photos/:photo_id/comments/:id/edit
|
||||
# PUT/PATCH /photos/:photo_id/comments/:id
|
||||
# DELETE /photos/:photo_id/comments/:id
|
||||
#
|
||||
# === Options
|
||||
# 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:
|
||||
#
|
||||
# post_comments GET /posts/:post_id/comments(.:format)
|
||||
# post_comments POST /posts/:post_id/comments(.:format)
|
||||
# new_post_comment GET /posts/:post_id/comments/new(.:format)
|
||||
# edit_comment GET /sekret/comments/:id/edit(.:format)
|
||||
# comment GET /sekret/comments/:id(.:format)
|
||||
# comment PUT /sekret/comments/:id(.:format)
|
||||
# comment DELETE /sekret/comments/:id(.:format)
|
||||
# post_comments GET /posts/:post_id/comments(.:format)
|
||||
# post_comments POST /posts/:post_id/comments(.:format)
|
||||
# new_post_comment GET /posts/:post_id/comments/new(.:format)
|
||||
# edit_comment GET /sekret/comments/:id/edit(.:format)
|
||||
# comment GET /sekret/comments/:id(.:format)
|
||||
# comment PUT/PATCH /sekret/comments/:id(.:format)
|
||||
# comment DELETE /sekret/comments/:id(.:format)
|
||||
#
|
||||
# === Examples
|
||||
#
|
||||
|
@ -1138,11 +1152,14 @@ module ActionDispatch
|
|||
get :new
|
||||
end if parent_resource.actions.include?(:new)
|
||||
|
||||
# TODO: Only accept patch or put depending on config
|
||||
member do
|
||||
get :edit if parent_resource.actions.include?(:edit)
|
||||
get :show if parent_resource.actions.include?(:show)
|
||||
put :update if parent_resource.actions.include?(:update)
|
||||
delete :destroy if parent_resource.actions.include?(:destroy)
|
||||
if parent_resource.actions.include?(:update)
|
||||
send default_method_for_update, :update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ module ActionDispatch
|
|||
# object's <tt>@response</tt> instance variable will point to the same
|
||||
# response object.
|
||||
#
|
||||
# You can also perform POST, PUT, DELETE, and HEAD requests with +#post+,
|
||||
# +#put+, +#delete+, and +#head+.
|
||||
# You can also perform POST, PATCH, PUT, DELETE, and HEAD requests with
|
||||
# +#post+, +#patch+, +#put+, +#delete+, and +#head+.
|
||||
def get(path, parameters = nil, headers = nil)
|
||||
process :get, path, parameters, headers
|
||||
end
|
||||
|
@ -38,6 +38,12 @@ module ActionDispatch
|
|||
process :post, path, parameters, headers
|
||||
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
|
||||
# details.
|
||||
def put(path, parameters = nil, headers = nil)
|
||||
|
@ -65,10 +71,10 @@ module ActionDispatch
|
|||
# Performs an XMLHttpRequest request with the given parameters, mirroring
|
||||
# a request from the Prototype library.
|
||||
#
|
||||
# The request_method is +:get+, +:post+, +:put+, +:delete+ or +:head+; the
|
||||
# parameters are +nil+, a hash, or a url-encoded or multipart string;
|
||||
# the headers are a hash. Keys are automatically upcased and prefixed
|
||||
# with 'HTTP_' if not already.
|
||||
# The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or
|
||||
# +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart
|
||||
# string; the headers are a hash. Keys are automatically upcased and
|
||||
# prefixed with 'HTTP_' if not already.
|
||||
def xml_http_request(request_method, path, parameters = nil, headers = nil)
|
||||
headers ||= {}
|
||||
headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||
|
@ -108,6 +114,12 @@ module ActionDispatch
|
|||
request_via_redirect(:post, path, parameters, headers)
|
||||
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.
|
||||
# See +request_via_redirect+ for more information.
|
||||
def put_via_redirect(path, parameters = nil, headers = nil)
|
||||
|
@ -318,7 +330,7 @@ module ActionDispatch
|
|||
@integration_session = Integration::Session.new(app)
|
||||
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|
|
||||
define_method(method) do |*args|
|
||||
reset! unless integration_session
|
||||
|
|
|
@ -132,6 +132,8 @@ module ActionView #:nodoc:
|
|||
class Base
|
||||
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.
|
||||
cattr_accessor :field_error_proc
|
||||
@@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
|
||||
#
|
||||
# :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
|
||||
# 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)
|
||||
|
||||
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!(
|
||||
:class => as ? "#{action}_#{as}" : dom_class(object, action),
|
||||
: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
|
||||
# the HTTP verb specified. Useful for having links perform a POST operation
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
|
@ -272,7 +272,7 @@ module ActionView
|
|||
#
|
||||
# There are a few special +html_options+:
|
||||
# * <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>:confirm</tt> - This will use the unobtrusive JavaScript driver to
|
||||
# prompt with the question specified. If the user accepts, the link is
|
||||
|
@ -329,7 +329,7 @@ module ActionView
|
|||
remote = html_options.delete('remote')
|
||||
|
||||
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_options = html_options.delete('form') || {}
|
||||
|
|
|
@ -33,6 +33,7 @@ module ActionView
|
|||
end
|
||||
|
||||
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
|
||||
app.config.action_view.each do |k,v|
|
||||
send "#{k}=", v
|
||||
|
|
|
@ -180,7 +180,7 @@ class PageCachingTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
[: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
|
||||
define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
|
||||
send(method, status)
|
||||
|
|
|
@ -63,6 +63,12 @@ class SessionTest < ActiveSupport::TestCase
|
|||
@session.post_via_redirect(path, args, headers)
|
||||
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
|
||||
path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue" }
|
||||
@session.expects(:request_via_redirect).with(:put, path, args, headers)
|
||||
|
@ -87,6 +93,12 @@ class SessionTest < ActiveSupport::TestCase
|
|||
@session.post(path,params,headers)
|
||||
end
|
||||
|
||||
def test_patch
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
@session.expects(:process).with(:patch,path,params,headers)
|
||||
@session.patch(path,params,headers)
|
||||
end
|
||||
|
||||
def test_put
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
@session.expects(:process).with(:put,path,params,headers)
|
||||
|
@ -131,6 +143,16 @@ class SessionTest < ActiveSupport::TestCase
|
|||
@session.xml_http_request(:post,path,params,headers)
|
||||
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
|
||||
path = "/index"; params = "blah"; headers = {:location => 'blah'}
|
||||
headers_after_xhr = headers.merge(
|
||||
|
@ -228,7 +250,7 @@ class IntegrationTestUsesCorrectClass < ActionDispatch::IntegrationTest
|
|||
@integration_session.stubs(:generic_url_rewriter)
|
||||
@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, '/') }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -770,6 +770,41 @@ class RespondWithControllerTest < ActionController::TestCase
|
|||
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
|
||||
with_test_route_set do
|
||||
put :using_resource
|
||||
|
|
|
@ -114,6 +114,10 @@ module RequestForgeryProtectionTests
|
|||
assert_blocked { post :index, :format=>'xml' }
|
||||
end
|
||||
|
||||
def test_should_not_allow_patch_without_token
|
||||
assert_blocked { patch :index }
|
||||
end
|
||||
|
||||
def test_should_not_allow_put_without_token
|
||||
assert_blocked { put :index }
|
||||
end
|
||||
|
@ -130,6 +134,10 @@ module RequestForgeryProtectionTests
|
|||
assert_not_blocked { post :index, :custom_authenticity_token => @token }
|
||||
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
|
||||
assert_not_blocked { put :index, :custom_authenticity_token => @token }
|
||||
end
|
||||
|
@ -148,6 +156,11 @@ module RequestForgeryProtectionTests
|
|||
assert_not_blocked { delete :index }
|
||||
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
|
||||
@request.env['HTTP_X_CSRF_TOKEN'] = @token
|
||||
assert_not_blocked { put :index }
|
||||
|
@ -232,7 +245,7 @@ class FreeCookieControllerTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
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)}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -158,7 +158,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
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|
|
||||
set.draw do
|
||||
|
@ -167,6 +167,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
put :b, :on => :collection
|
||||
post :c, :on => :collection
|
||||
delete :d, :on => :collection
|
||||
patch :e, :on => :collection
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -185,7 +186,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
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|
|
||||
set.draw do
|
||||
|
@ -195,6 +196,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
put :b, :on => :collection
|
||||
post :c, :on => :collection
|
||||
delete :d, :on => :collection
|
||||
patch :e, :on => :collection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -241,7 +243,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
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|
|
||||
set.draw do
|
||||
|
@ -251,6 +253,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
put :b, :on => :collection
|
||||
post :c, :on => :collection
|
||||
delete :d, :on => :collection
|
||||
patch :e, :on => :collection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -270,7 +273,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_with_member_action
|
||||
[:put, :post].each do |method|
|
||||
[:patch, :put, :post].each do |method|
|
||||
with_restful_routing :messages, :member => { :mark => method } do
|
||||
mark_options = {:action => 'mark', :id => '1'}
|
||||
mark_path = "/messages/1/mark"
|
||||
|
@ -294,7 +297,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
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
|
||||
mark_options = {:action => 'mark', :id => '1', :controller => "messages"}
|
||||
mark_path = "/messages/1/mark"
|
||||
|
@ -311,7 +314,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_with_two_member_actions_with_same_method
|
||||
[:put, :post].each do |method|
|
||||
[:patch, :put, :post].each do |method|
|
||||
with_routing do |set|
|
||||
set.draw do
|
||||
resources :messages do
|
||||
|
@ -564,7 +567,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_singleton_resource_with_member_action
|
||||
[:put, :post].each do |method|
|
||||
[:patch, :put, :post].each do |method|
|
||||
with_routing do |set|
|
||||
set.draw do
|
||||
resource :account do
|
||||
|
@ -586,7 +589,7 @@ class ResourcesTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
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|
|
||||
set.draw do
|
||||
resource :account do
|
||||
|
@ -651,12 +654,16 @@ class ResourcesTest < ActionController::TestCase
|
|||
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
|
||||
with_restful_routing controller_name do
|
||||
options = { :controller => controller_name.to_s }
|
||||
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_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put)
|
||||
end
|
||||
|
|
|
@ -648,11 +648,12 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
|
|||
match '/match' => 'books#get', :via => :get
|
||||
match '/match' => 'books#post', :via => :post
|
||||
match '/match' => 'books#put', :via => :put
|
||||
match '/match' => 'books#patch', :via => :patch
|
||||
match '/match' => 'books#delete', :via => :delete
|
||||
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
|
||||
setup_request_method_routes_for(request_method)
|
||||
params = rs.recognize_path("/match", :method => request_method)
|
||||
|
@ -1035,6 +1036,7 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
post "/people" => "people#create"
|
||||
get "/people/:id" => "people#show", :as => "person"
|
||||
put "/people/:id" => "people#update"
|
||||
patch "/people/:id" => "people#update"
|
||||
delete "/people/:id" => "people#destroy"
|
||||
end
|
||||
|
||||
|
@ -1047,6 +1049,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
params = set.recognize_path("/people/5", :method => :put)
|
||||
assert_equal("update", params[:action])
|
||||
|
||||
params = set.recognize_path("/people/5", :method => :patch)
|
||||
assert_equal("update", params[:action])
|
||||
|
||||
assert_raise(ActionController::UnknownHttpMethod) {
|
||||
set.recognize_path("/people", :method => :bacon)
|
||||
}
|
||||
|
@ -1059,6 +1064,10 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
assert_equal("update", params[:action])
|
||||
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)
|
||||
assert_equal("destroy", params[:action])
|
||||
assert_equal("5", params[:id])
|
||||
|
@ -1112,6 +1121,7 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
set.draw do
|
||||
get "people/:id" => "people#show", :as => "person"
|
||||
put "people/:id" => "people#update"
|
||||
patch "people/:id" => "people#update"
|
||||
get "people/:id(.:format)" => "people#show"
|
||||
end
|
||||
|
||||
|
@ -1122,6 +1132,9 @@ class RouteSetTest < ActiveSupport::TestCase
|
|||
params = set.recognize_path("/people/5", :method => :put)
|
||||
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)
|
||||
assert_equal("show", params[:action])
|
||||
assert_equal("5", params[:id])
|
||||
|
|
|
@ -325,14 +325,14 @@ class RequestTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
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
|
||||
assert_equal method.to_s.upcase, request.method
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
assert_equal method, request.method_symbol
|
||||
end
|
||||
|
@ -346,7 +346,7 @@ class RequestTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
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
|
||||
assert_equal(method == "HEAD" ? "GET" : method, request.method)
|
||||
end
|
||||
|
@ -360,7 +360,7 @@ class RequestTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
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,
|
||||
'action_dispatch.request.request_parameters' => { :_method => 'put' }
|
||||
assert_equal method.to_s.upcase, request.method
|
||||
|
@ -375,6 +375,13 @@ class RequestTest < ActiveSupport::TestCase
|
|||
assert request.head?
|
||||
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
|
||||
request = stub_request 'REQUEST_METHOD' => 'PUT', "rack.methodoverride.original_method" => "POST"
|
||||
assert_equal "POST", request.method
|
||||
|
|
|
@ -2195,6 +2195,15 @@ class FormHelperTest < ActionView::TestCase
|
|||
assert_equal expected, output_buffer
|
||||
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
|
||||
output = fields_for(Post.new) { |f| "fields" }
|
||||
assert_equal "fields", output
|
||||
|
|
|
@ -78,6 +78,12 @@ class FormTagHelperTest < ActionView::TestCase
|
|||
assert_dom_equal expected, actual
|
||||
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
|
||||
actual = form_tag({}, { :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.
|
||||
# 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
|
||||
# collection. If it is persisted, a form for the object will be PUT to the
|
||||
# URL for the object.
|
||||
# not persisted, a form for that object, for instance, will route to the
|
||||
# create action. If it is persisted, a form for the object will routes to
|
||||
# the update action.
|
||||
def test_persisted?
|
||||
assert model.respond_to?(:persisted?), "The model should respond to persisted?"
|
||||
assert_boolean model.persisted?, "persisted?"
|
||||
|
|
|
@ -15,6 +15,7 @@ module ActiveResource
|
|||
HTTP_FORMAT_HEADER_NAMES = { :get => 'Accept',
|
||||
:put => 'Content-Type',
|
||||
:post => 'Content-Type',
|
||||
:patch => 'Content-Type',
|
||||
:delete => 'Accept',
|
||||
:head => 'Accept'
|
||||
}
|
||||
|
@ -86,6 +87,12 @@ module ActiveResource
|
|||
with_auth { request(:delete, path, build_request_headers(headers, :delete, self.site.merge(path))) }
|
||||
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).
|
||||
# Used to update resources.
|
||||
def put(path, body = '', headers = {})
|
||||
|
|
|
@ -11,10 +11,10 @@ module ActiveResource
|
|||
#
|
||||
# This route set creates routes for the following HTTP requests:
|
||||
#
|
||||
# POST /people/new/register.json # PeopleController.register
|
||||
# PUT /people/1/promote.json # PeopleController.promote with :id => 1
|
||||
# DELETE /people/1/deactivate.json # PeopleController.deactivate with :id => 1
|
||||
# GET /people/active.json # PeopleController.active
|
||||
# POST /people/new/register.json # PeopleController.register
|
||||
# PUT/PATCH /people/1/promote.json # PeopleController.promote with :id => 1
|
||||
# DELETE /people/1/deactivate.json # PeopleController.deactivate with :id => 1
|
||||
# GET /people/active.json # PeopleController.active
|
||||
#
|
||||
# Using this module, Active Resource can use these custom REST methods just like the
|
||||
# standard methods.
|
||||
|
@ -63,6 +63,10 @@ module ActiveResource
|
|||
connection.post(custom_method_collection_url(custom_method_name, options), body, headers)
|
||||
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 = '')
|
||||
connection.put(custom_method_collection_url(custom_method_name, options), body, headers)
|
||||
end
|
||||
|
@ -98,6 +102,10 @@ module ActiveResource
|
|||
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 = '')
|
||||
connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ module ActiveResource
|
|||
#
|
||||
# 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+.
|
||||
# * <tt>path</tt> - A string, starting with a "/", defining the URI that is expected to be
|
||||
# called.
|
||||
|
@ -55,7 +55,7 @@ module ActiveResource
|
|||
@responses = responses
|
||||
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 = {})
|
||||
# @responses[Request.new(:post, path, nil, request_headers)] = Response.new(body || "", status, response_headers)
|
||||
# end
|
||||
|
@ -217,7 +217,7 @@ module ActiveResource
|
|||
end
|
||||
|
||||
# body? methods
|
||||
{ true => %w(post put),
|
||||
{ true => %w(post patch put),
|
||||
false => %w(get delete head) }.each do |has_body, methods|
|
||||
methods.each do |method|
|
||||
# def post(path, body, headers)
|
||||
|
|
|
@ -11,11 +11,15 @@ class FormatTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def test_http_format_header_name
|
||||
header_name = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:get]
|
||||
assert_equal 'Accept', header_name
|
||||
[:get, :head].each do |verb|
|
||||
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]]
|
||||
headers_names.each{ |name| assert_equal 'Content-Type', name }
|
||||
[:patch, :put, :post].each do |verb|
|
||||
header_name = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[verb]
|
||||
assert_equal 'Content-Type', header_name
|
||||
end
|
||||
end
|
||||
|
||||
def test_formats_on_single_element
|
||||
|
|
|
@ -8,7 +8,7 @@ class HttpMockTest < ActiveSupport::TestCase
|
|||
|
||||
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
|
||||
ActiveResource::HttpMock.respond_to do |mock|
|
||||
mock.send(method, "/people/1", { FORMAT_HEADER[method] => "application/json" }, "Response")
|
||||
|
@ -193,7 +193,7 @@ class HttpMockTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def request(method, path, headers = {}, body = nil)
|
||||
if method.in?([:put, :post])
|
||||
if method.in?([:patch, :put, :post])
|
||||
@http.send(method, path, body, headers)
|
||||
else
|
||||
@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).|
|
||||
|format|The content type requested by the client.|
|
||||
|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.|
|
||||
|port|The port number (integer) used for the request.|
|
||||
|protocol|Returns a string containing the protocol used plus "://", for example "http://".|
|
||||
|
|
|
@ -146,7 +146,8 @@ link_to_remote "Add new item",
|
|||
:position => :bottom
|
||||
</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>
|
||||
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.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.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::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+.
|
||||
* +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::BestStandardsSupport+ enables "best standards support" so that IE8 renders some elements correctly.
|
||||
|
||||
|
@ -346,7 +348,8 @@ h4. Configuring Action Dispatch
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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:
|
||||
|
||||
<ruby>
|
||||
form_tag(search_path, :method => "put")
|
||||
form_tag(search_path, :method => "patch")
|
||||
</ruby>
|
||||
|
||||
output:
|
||||
|
@ -335,14 +340,14 @@ output:
|
|||
<html>
|
||||
<form accept-charset="UTF-8" action="/search" method="post">
|
||||
<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="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
|
||||
</div>
|
||||
...
|
||||
</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
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ Resource routing allows you to quickly declare all of the common routes for a gi
|
|||
|
||||
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
|
||||
|
||||
|
@ -82,11 +82,10 @@ creates seven different routes in your application, all mapping to the +Photos+
|
|||
|POST |/photos |create |create a new photo |
|
||||
|GET |/photos/:id |show |display a specific 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 |
|
||||
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 |
|
||||
|GET |/geocoder |show |display the one and only geocoder resource |
|
||||
|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 |
|
||||
|
||||
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:
|
||||
|
||||
|
@ -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 |
|
||||
|GET |/admin/posts/:id |show | 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) |
|
||||
|
||||
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
|
||||
|
||||
<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 |
|
||||
|GET |/admin/posts/:id |show | 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) |
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
|_.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/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 |
|
||||
|_.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/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 |
|
||||
|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 |
|
||||
|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 |
|
||||
|
||||
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)+).
|
||||
|
||||
|
@ -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.
|
||||
|
||||
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>
|
||||
resources :photos do
|
||||
|
@ -642,7 +646,7 @@ will recognize incoming paths beginning with +/photos+ but route to the +Images+
|
|||
|POST |/photos |create | photos_path |
|
||||
|GET |/photos/:id |show | 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) |
|
||||
|
||||
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 |
|
||||
|GET |/photos/:id |show | 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) |
|
||||
|
||||
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
|
||||
|
||||
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 |
|
||||
|GET |/kategorien/:id |show | 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) |
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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+
|
||||
* +post+
|
||||
* +patch+
|
||||
* +put+
|
||||
* +head+
|
||||
* +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.|
|
||||
|+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.|
|
||||
|+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.|
|
||||
|+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.|
|
||||
|
@ -810,7 +812,7 @@ class PostsControllerTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
test "should update post" do
|
||||
put :update, :id => @post.id, :post => { }
|
||||
patch :update, :id => @post.id, :post => { }
|
||||
assert_redirected_to post_path(assigns(:post))
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module Rails
|
|||
:force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks,
|
||||
:railties_order, :relative_url_root, :secret_token,
|
||||
: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_reader :encoding
|
||||
|
@ -40,6 +40,7 @@ module Rails
|
|||
@reload_classes_only_on_change = true
|
||||
@file_watcher = ActiveSupport::FileUpdateChecker
|
||||
@exceptions_app = nil
|
||||
@default_method_for_update = :put
|
||||
|
||||
@assets = ActiveSupport::OrderedOptions.new
|
||||
@assets.enabled = false
|
||||
|
|
|
@ -37,7 +37,7 @@ module Rails
|
|||
|
||||
# GET show
|
||||
# GET edit
|
||||
# PUT update
|
||||
# PUT/PATCH update
|
||||
# DELETE destroy
|
||||
def self.find(klass, params=nil)
|
||||
"#{klass}.find(#{params})"
|
||||
|
@ -58,13 +58,13 @@ module Rails
|
|||
"#{name}.save"
|
||||
end
|
||||
|
||||
# PUT update
|
||||
# PUT/PATCH update
|
||||
def update_attributes(params=nil)
|
||||
"#{name}.update_attributes(#{params})"
|
||||
end
|
||||
|
||||
# POST create
|
||||
# PUT update
|
||||
# PUT/PATCH update
|
||||
def errors
|
||||
"#{name}.errors"
|
||||
end
|
||||
|
|
|
@ -31,6 +31,9 @@ module <%= app_const_base %>
|
|||
# Activate observers that should always be running.
|
||||
# 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.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||
# config.time_zone = 'Central Time (US & Canada)'
|
||||
|
|
|
@ -54,8 +54,8 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# PUT <%= route_url %>/1
|
||||
# PUT <%= route_url %>/1.json
|
||||
# PUT/PATCH <%= route_url %>/1
|
||||
# PUT/PATCH <%= route_url %>/1.json
|
||||
def update
|
||||
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ module ApplicationTests
|
|||
test "frameworks are not preloaded by default" do
|
||||
require "#{app_path}/config/environment"
|
||||
|
||||
assert ActionController.autoload?(:RecordIdentifier)
|
||||
assert ActionController.autoload?(:Caching)
|
||||
end
|
||||
|
||||
test "frameworks are preloaded with config.preload_frameworks is set" do
|
||||
|
@ -156,7 +156,7 @@ module ApplicationTests
|
|||
|
||||
require "#{app_path}/config/environment"
|
||||
|
||||
assert !ActionController.autoload?(:RecordIdentifier)
|
||||
assert !ActionController.autoload?(:Caching)
|
||||
end
|
||||
|
||||
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/
|
||||
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
|
||||
make_basic_app do
|
||||
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["']/
|
||||
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
|
||||
run_generator [destination_root]
|
||||
assert_file "config/initializers/session_store.rb" do |file|
|
||||
|
|
Loading…
Reference in a new issue