Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
bf5b6969
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
bf5b6969
编写于
8月 17, 2014
作者:
J
José Valim
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #16526 from rails/jv-no-responders
Move respond_with to the responders gem
上级
aee1ba42
57f5b00b
变更
14
展开全部
隐藏空白更改
内联
并排
Showing
14 changed file
with
16 addition
and
1276 deletion
+16
-1276
actionpack/CHANGELOG.md
actionpack/CHANGELOG.md
+5
-0
actionpack/lib/action_controller/metal/mime_responds.rb
actionpack/lib/action_controller/metal/mime_responds.rb
+3
-231
actionpack/lib/action_controller/metal/responder.rb
actionpack/lib/action_controller/metal/responder.rb
+0
-297
actionpack/test/controller/mime/respond_with_test.rb
actionpack/test/controller/mime/respond_with_test.rb
+0
-737
actionpack/test/fixtures/respond_with/edit.html.erb
actionpack/test/fixtures/respond_with/edit.html.erb
+0
-1
actionpack/test/fixtures/respond_with/new.html.erb
actionpack/test/fixtures/respond_with/new.html.erb
+0
-1
actionpack/test/fixtures/respond_with/respond_with_additional_params.html.erb
...ures/respond_with/respond_with_additional_params.html.erb
+0
-0
actionpack/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb
...respond_with/using_invalid_resource_with_template.xml.erb
+0
-1
actionpack/test/fixtures/respond_with/using_options_with_template.xml.erb
...fixtures/respond_with/using_options_with_template.xml.erb
+0
-1
actionpack/test/fixtures/respond_with/using_resource.js.erb
actionpack/test/fixtures/respond_with/using_resource.js.erb
+0
-1
actionpack/test/fixtures/respond_with/using_resource_with_block.html.erb
.../fixtures/respond_with/using_resource_with_block.html.erb
+0
-1
actionview/test/activerecord/controller_runtime_test.rb
actionview/test/activerecord/controller_runtime_test.rb
+1
-3
guides/source/caching_with_rails.md
guides/source/caching_with_rails.md
+6
-1
guides/source/contributing_to_ruby_on_rails.md
guides/source/contributing_to_ruby_on_rails.md
+1
-1
未找到文件。
actionpack/CHANGELOG.md
浏览文件 @
bf5b6969
*
Move
`respond_with`
(and the class-level
`respond_to`
) to
the
`responders`
gem.
*José Valim*
*
When your templates change, browser caches bust automatically.
New default: the template digest is automatically included in your ETags.
...
...
actionpack/lib/action_controller/metal/mime_responds.rb
浏览文件 @
bf5b6969
...
...
@@ -5,58 +5,6 @@ module ActionController #:nodoc:
module
MimeResponds
extend
ActiveSupport
::
Concern
included
do
class_attribute
:responder
,
:mimes_for_respond_to
self
.
responder
=
ActionController
::
Responder
clear_respond_to
end
module
ClassMethods
# Defines mime types that are rendered by default when invoking
# <tt>respond_with</tt>.
#
# respond_to :html, :xml, :json
#
# Specifies that all actions in the controller respond to requests
# for <tt>:html</tt>, <tt>:xml</tt> and <tt>:json</tt>.
#
# To specify on per-action basis, use <tt>:only</tt> and
# <tt>:except</tt> with an array of actions or a single action:
#
# respond_to :html
# respond_to :xml, :json, except: [ :edit ]
#
# This specifies that all actions respond to <tt>:html</tt>
# and all actions except <tt>:edit</tt> respond to <tt>:xml</tt> and
# <tt>:json</tt>.
#
# respond_to :json, only: :create
#
# This specifies that the <tt>:create</tt> action and no other responds
# to <tt>:json</tt>.
def
respond_to
(
*
mimes
)
options
=
mimes
.
extract_options!
only_actions
=
Array
(
options
.
delete
(
:only
)).
map
(
&
:to_s
)
except_actions
=
Array
(
options
.
delete
(
:except
)).
map
(
&
:to_s
)
new
=
mimes_for_respond_to
.
dup
mimes
.
each
do
|
mime
|
mime
=
mime
.
to_sym
new
[
mime
]
=
{}
new
[
mime
][
:only
]
=
only_actions
unless
only_actions
.
empty?
new
[
mime
][
:except
]
=
except_actions
unless
except_actions
.
empty?
end
self
.
mimes_for_respond_to
=
new
.
freeze
end
# Clear all mime types in <tt>respond_to</tt>.
#
def
clear_respond_to
self
.
mimes_for_respond_to
=
Hash
.
new
.
freeze
end
end
# Without web-service support, an action which collects the data for displaying a list of people
# might look something like this:
#
...
...
@@ -253,189 +201,13 @@ def clear_respond_to
def
respond_to
(
*
mimes
,
&
block
)
raise
ArgumentError
,
"respond_to takes either types or a block, never both"
if
mimes
.
any?
&&
block_given?
if
collector
=
retrieve_collector_from_mimes
(
mimes
,
&
block
)
response
=
collector
.
response
response
?
response
.
call
:
render
({})
end
end
# For a given controller action, respond_with generates an appropriate
# response based on the mime-type requested by the client.
#
# If the method is called with just a resource, as in this example -
#
# class PeopleController < ApplicationController
# respond_to :html, :xml, :json
#
# def index
# @people = Person.all
# respond_with @people
# end
# end
#
# then the mime-type of the response is typically selected based on the
# request's Accept header and the set of available formats declared
# by previous calls to the controller's class method +respond_to+. Alternatively
# the mime-type can be selected by explicitly setting <tt>request.format</tt> in
# the controller.
#
# If an acceptable format is not identified, the application returns a
# '406 - not acceptable' status. Otherwise, the default response is to render
# a template named after the current action and the selected format,
# e.g. <tt>index.html.erb</tt>. If no template is available, the behavior
# depends on the selected format:
#
# * for an html response - if the request method is +get+, an exception
# is raised but for other requests such as +post+ the response
# depends on whether the resource has any validation errors (i.e.
# assuming that an attempt has been made to save the resource,
# e.g. by a +create+ action) -
# 1. If there are no errors, i.e. the resource
# was saved successfully, the response +redirect+'s to the resource
# i.e. its +show+ action.
# 2. If there are validation errors, the response
# renders a default action, which is <tt>:new</tt> for a
# +post+ request or <tt>:edit</tt> for +patch+ or +put+.
# Thus an example like this -
#
# respond_to :html, :xml
#
# def create
# @user = User.new(params[:user])
# flash[:notice] = 'User was successfully created.' if @user.save
# respond_with(@user)
# end
#
# is equivalent, in the absence of <tt>create.html.erb</tt>, to -
#
# def create
# @user = User.new(params[:user])
# respond_to do |format|
# if @user.save
# flash[:notice] = 'User was successfully created.'
# format.html { redirect_to(@user) }
# format.xml { render xml: @user }
# else
# format.html { render action: "new" }
# format.xml { render xml: @user }
# end
# end
# end
#
# * for a JavaScript request - if the template isn't found, an exception is
# raised.
# * for other requests - i.e. data formats such as xml, json, csv etc, if
# the resource passed to +respond_with+ responds to <code>to_<format></code>,
# the method attempts to render the resource in the requested format
# directly, e.g. for an xml request, the response is equivalent to calling
# <code>render xml: resource</code>.
#
# === Nested resources
#
# As outlined above, the +resources+ argument passed to +respond_with+
# can play two roles. It can be used to generate the redirect url
# for successful html requests (e.g. for +create+ actions when
# no template exists), while for formats other than html and JavaScript
# it is the object that gets rendered, by being converted directly to the
# required format (again assuming no template exists).
#
# For redirecting successful html requests, +respond_with+ also supports
# the use of nested resources, which are supplied in the same way as
# in <code>form_for</code> and <code>polymorphic_url</code>. For example -
#
# def create
# @project = Project.find(params[:project_id])
# @task = @project.comments.build(params[:task])
# flash[:notice] = 'Task was successfully created.' if @task.save
# respond_with(@project, @task)
# end
#
# This would cause +respond_with+ to redirect to <code>project_task_url</code>
# instead of <code>task_url</code>. For request formats other than html or
# JavaScript, if multiple resources are passed in this way, it is the last
# one specified that is rendered.
#
# === Customizing response behavior
#
# Like +respond_to+, +respond_with+ may also be called with a block that
# can be used to overwrite any of the default responses, e.g. -
#
# def create
# @user = User.new(params[:user])
# flash[:notice] = "User was successfully created." if @user.save
#
# respond_with(@user) do |format|
# format.html { render }
# end
# end
#
# The argument passed to the block is an ActionController::MimeResponds::Collector
# object which stores the responses for the formats defined within the
# block. Note that formats with responses defined explicitly in this way
# do not have to first be declared using the class method +respond_to+.
#
# Also, a hash passed to +respond_with+ immediately after the specified
# resource(s) is interpreted as a set of options relevant to all
# formats. Any option accepted by +render+ can be used, e.g.
# respond_with @people, status: 200
# However, note that these options are ignored after an unsuccessful attempt
# to save a resource, e.g. when automatically rendering <tt>:new</tt>
# after a post request.
#
# Two additional options are relevant specifically to +respond_with+ -
# 1. <tt>:location</tt> - overwrites the default redirect location used after
# a successful html +post+ request.
# 2. <tt>:action</tt> - overwrites the default render action used after an
# unsuccessful html +post+ request.
def
respond_with
(
*
resources
,
&
block
)
if
self
.
class
.
mimes_for_respond_to
.
empty?
raise
"In order to use respond_with, first you need to declare the "
\
"formats your controller responds to in the class level."
end
if
collector
=
retrieve_collector_from_mimes
(
&
block
)
options
=
resources
.
size
==
1
?
{}
:
resources
.
extract_options!
options
=
options
.
clone
options
[
:default_response
]
=
collector
.
response
(
options
.
delete
(
:responder
)
||
self
.
class
.
responder
).
call
(
self
,
resources
,
options
)
end
end
protected
# Collect mimes declared in the class method respond_to valid for the
# current action.
def
collect_mimes_from_class_level
#:nodoc:
action
=
action_name
.
to_s
self
.
class
.
mimes_for_respond_to
.
keys
.
select
do
|
mime
|
config
=
self
.
class
.
mimes_for_respond_to
[
mime
]
if
config
[
:except
]
!
config
[
:except
].
include?
(
action
)
elsif
config
[
:only
]
config
[
:only
].
include?
(
action
)
else
true
end
end
end
# Returns a Collector object containing the appropriate mime-type response
# for the current request, based on the available responses defined by a block.
# In typical usage this is the block passed to +respond_with+ or +respond_to+.
#
# Sends :not_acceptable to the client and returns nil if no suitable format
# is available.
def
retrieve_collector_from_mimes
(
mimes
=
nil
,
&
block
)
#:nodoc:
mimes
||=
collect_mimes_from_class_level
collector
=
Collector
.
new
(
mimes
,
request
.
variant
)
block
.
call
(
collector
)
if
block_given?
format
=
collector
.
negotiate_format
(
request
)
if
format
if
format
=
collector
.
negotiate_format
(
request
)
_process_format
(
format
)
collector
response
=
collector
.
response
response
?
response
.
call
:
render
({})
else
raise
ActionController
::
UnknownFormat
end
...
...
actionpack/lib/action_controller/metal/responder.rb
已删除
100644 → 0
浏览文件 @
aee1ba42
require
'active_support/json'
module
ActionController
#:nodoc:
# Responsible for exposing a resource to different mime requests,
# usually depending on the HTTP verb. The responder is triggered when
# <code>respond_with</code> is called. The simplest case to study is a GET request:
#
# class PeopleController < ApplicationController
# respond_to :html, :xml, :json
#
# def index
# @people = Person.all
# respond_with(@people)
# end
# end
#
# When a request comes in, for example for an XML response, three steps happen:
#
# 1) the responder searches for a template at people/index.xml;
#
# 2) if the template is not available, it will invoke <code>#to_xml</code> on the given resource;
#
# 3) if the responder does not <code>respond_to :to_xml</code>, call <code>#to_format</code> on it.
#
# === Built-in HTTP verb semantics
#
# The default \Rails responder holds semantics for each HTTP verb. Depending on the
# content type, verb and the resource status, it will behave differently.
#
# Using \Rails default responder, a POST request for creating an object could
# be written as:
#
# def create
# @user = User.new(params[:user])
# flash[:notice] = 'User was successfully created.' if @user.save
# respond_with(@user)
# end
#
# Which is exactly the same as:
#
# def create
# @user = User.new(params[:user])
#
# respond_to do |format|
# if @user.save
# flash[:notice] = 'User was successfully created.'
# format.html { redirect_to(@user) }
# format.xml { render xml: @user, status: :created, location: @user }
# else
# format.html { render action: "new" }
# format.xml { render xml: @user.errors, status: :unprocessable_entity }
# end
# end
# end
#
# The same happens for PATCH/PUT and DELETE requests.
#
# === Nested resources
#
# You can supply nested resources as you do in <code>form_for</code> and <code>polymorphic_url</code>.
# Consider the project has many tasks example. The create action for
# TasksController would be like:
#
# def create
# @project = Project.find(params[:project_id])
# @task = @project.tasks.build(params[:task])
# flash[:notice] = 'Task was successfully created.' if @task.save
# respond_with(@project, @task)
# end
#
# Giving several resources ensures that the responder will redirect to
# <code>project_task_url</code> instead of <code>task_url</code>.
#
# Namespaced and singleton resources require a symbol to be given, as in
# polymorphic urls. If a project has one manager which has many tasks, it
# should be invoked as:
#
# respond_with(@project, :manager, @task)
#
# Note that if you give an array, it will be treated as a collection,
# so the following is not equivalent:
#
# respond_with [@project, :manager, @task]
#
# === Custom options
#
# <code>respond_with</code> also allows you to pass options that are forwarded
# to the underlying render call. Those options are only applied for success
# scenarios. For instance, you can do the following in the create method above:
#
# def create
# @project = Project.find(params[:project_id])
# @task = @project.tasks.build(params[:task])
# flash[:notice] = 'Task was successfully created.' if @task.save
# respond_with(@project, @task, status: 201)
# end
#
# This will return status 201 if the task was saved successfully. If not,
# it will simply ignore the given options and return status 422 and the
# resource errors. You can also override the location to redirect to:
#
# respond_with(@project, location: root_path)
#
# To customize the failure scenario, you can pass a block to
# <code>respond_with</code>:
#
# def create
# @project = Project.find(params[:project_id])
# @task = @project.tasks.build(params[:task])
# respond_with(@project, @task, status: 201) do |format|
# if @task.save
# flash[:notice] = 'Task was successfully created.'
# else
# format.html { render "some_special_template" }
# end
# end
# end
#
# Using <code>respond_with</code> with a block follows the same syntax as <code>respond_to</code>.
class
Responder
attr_reader
:controller
,
:request
,
:format
,
:resource
,
:resources
,
:options
DEFAULT_ACTIONS_FOR_VERBS
=
{
:post
=>
:new
,
:patch
=>
:edit
,
:put
=>
:edit
}
def
initialize
(
controller
,
resources
,
options
=
{})
@controller
=
controller
@request
=
@controller
.
request
@format
=
@controller
.
formats
.
first
@resource
=
resources
.
last
@resources
=
resources
@options
=
options
@action
=
options
.
delete
(
:action
)
@default_response
=
options
.
delete
(
:default_response
)
end
delegate
:head
,
:render
,
:redirect_to
,
:to
=>
:controller
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
)
undef_method
(
:to_yaml
)
if
method_defined?
(
:to_yaml
)
# Initializes a new responder and invokes the proper format. If the format is
# not defined, call to_format.
#
def
self
.
call
(
*
args
)
new
(
*
args
).
respond
end
# Main entry point for responder responsible to dispatch to the proper format.
#
def
respond
method
=
"to_
#{
format
}
"
respond_to?
(
method
)
?
send
(
method
)
:
to_format
end
# HTML format does not render the resource, it always attempt to render a
# template.
#
def
to_html
default_render
rescue
ActionView
::
MissingTemplate
=>
e
navigation_behavior
(
e
)
end
# to_js simply tries to render a template. If no template is found, raises the error.
def
to_js
default_render
end
# All other formats follow the procedure below. First we try to render a
# template, if the template is not available, we verify if the resource
# responds to :to_format and display it.
#
def
to_format
if
get?
||
!
has_errors?
||
response_overridden?
default_render
else
display_errors
end
rescue
ActionView
::
MissingTemplate
=>
e
api_behavior
(
e
)
end
protected
# This is the common behavior for formats associated with browsing, like :html, :iphone and so forth.
def
navigation_behavior
(
error
)
if
get?
raise
error
elsif
has_errors?
&&
default_action
render
:action
=>
default_action
else
redirect_to
navigation_location
end
end
# This is the common behavior for formats associated with APIs, such as :xml and :json.
def
api_behavior
(
error
)
raise
error
unless
resourceful?
raise
MissingRenderer
.
new
(
format
)
unless
has_renderer?
if
get?
display
resource
elsif
post?
display
resource
,
:status
=>
:created
,
:location
=>
api_location
else
head
:no_content
end
end
# Checks whether the resource responds to the current format or not.
#
def
resourceful?
resource
.
respond_to?
(
"to_
#{
format
}
"
)
end
# Returns the resource location by retrieving it from the options or
# returning the resources array.
#
def
resource_location
options
[
:location
]
||
resources
end
alias
:navigation_location
:resource_location
alias
:api_location
:resource_location
# If a response block was given, use it, otherwise call render on
# controller.
#
def
default_render
if
@default_response
@default_response
.
call
(
options
)
else
controller
.
default_render
(
options
)
end
end
# Display is just a shortcut to render a resource with the current format.
#
# display @user, status: :ok
#
# For XML requests it's equivalent to:
#
# render xml: @user, status: :ok
#
# Options sent by the user are also used:
#
# respond_with(@user, status: :created)
# display(@user, status: :ok)
#
# Results in:
#
# render xml: @user, status: :created
#
def
display
(
resource
,
given_options
=
{})
controller
.
render
given_options
.
merge!
(
options
).
merge!
(
format
=>
resource
)
end
def
display_errors
controller
.
render
format
=>
resource_errors
,
:status
=>
:unprocessable_entity
end
# Check whether the resource has errors.
#
def
has_errors?
resource
.
respond_to?
(
:errors
)
&&
!
resource
.
errors
.
empty?
end
# Check whether the necessary Renderer is available
def
has_renderer?
Renderers
::
RENDERERS
.
include?
(
format
)
end
# By default, render the <code>:edit</code> action for HTML requests with errors, unless
# the verb was POST.
#
def
default_action
@action
||=
DEFAULT_ACTIONS_FOR_VERBS
[
request
.
request_method_symbol
]
end
def
resource_errors
respond_to?
(
"
#{
format
}
_resource_errors"
,
true
)
?
send
(
"
#{
format
}
_resource_errors"
)
:
resource
.
errors
end
def
json_resource_errors
{
:errors
=>
resource
.
errors
}
end
def
response_overridden?
@default_response
.
present?
end
end
end
actionpack/test/controller/mime/respond_with_test.rb
已删除
100644 → 0
浏览文件 @
aee1ba42
此差异已折叠。
点击以展开。
actionpack/test/fixtures/respond_with/edit.html.erb
已删除
100644 → 0
浏览文件 @
aee1ba42
Edit world!
actionpack/test/fixtures/respond_with/new.html.erb
已删除
100644 → 0
浏览文件 @
aee1ba42
New world!
actionpack/test/fixtures/respond_with/respond_with_additional_params.html.erb
已删除
100644 → 0
浏览文件 @
aee1ba42
actionpack/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb
已删除
100644 → 0
浏览文件 @
aee1ba42
<content>
I should not be displayed
</content>
\ No newline at end of file
actionpack/test/fixtures/respond_with/using_options_with_template.xml.erb
已删除
100644 → 0
浏览文件 @
aee1ba42
<customer-name>
<%=
@customer
.
name
%>
</customer-name>
\ No newline at end of file
actionpack/test/fixtures/respond_with/using_resource.js.erb
已删除
100644 → 0
浏览文件 @
aee1ba42
alert("Hi");
\ No newline at end of file
actionpack/test/fixtures/respond_with/using_resource_with_block.html.erb
已删除
100644 → 0
浏览文件 @
aee1ba42
Hello world!
\ No newline at end of file
actionview/test/activerecord/controller_runtime_test.rb
浏览文件 @
bf5b6969
...
...
@@ -8,8 +8,6 @@
class
ControllerRuntimeLogSubscriberTest
<
ActionController
::
TestCase
class
LogSubscriberController
<
ActionController
::
Base
respond_to
:html
def
show
render
:inline
=>
"<%= Project.all %>"
end
...
...
@@ -21,7 +19,7 @@ def zero
def
create
ActiveRecord
::
LogSubscriber
.
runtime
+=
100
project
=
Project
.
last
re
spond_with
(
project
,
location:
url_for
(
action: :show
))
re
direct_to
"/"
end
def
redirect
...
...
guides/source/caching_with_rails.md
浏览文件 @
bf5b6969
...
...
@@ -353,7 +353,12 @@ Instead of an options hash, you can also simply pass in a model, Rails will use
class
ProductsController
<
ApplicationController
def
show
@product
=
Product
.
find
(
params
[
:id
])
respond_with
(
@product
)
if
stale?
(
@product
)
if
stale?
(
@product
)
respond_to
do
|
wants
|
# ... normal response processing
end
end
end
end
```
...
...
guides/source/contributing_to_ruby_on_rails.md
浏览文件 @
bf5b6969
...
...
@@ -397,7 +397,7 @@ inside, just indent it with 4 spaces:
class ArticlesController
def index
re
spond_with
Article.limit(10)
re
nder json:
Article.limit(10)
end
end
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录