halorgium-actionpack 3.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5179 -0
- data/MIT-LICENSE +21 -0
- data/README +409 -0
- data/lib/abstract_controller.rb +16 -0
- data/lib/abstract_controller/base.rb +158 -0
- data/lib/abstract_controller/callbacks.rb +113 -0
- data/lib/abstract_controller/exceptions.rb +12 -0
- data/lib/abstract_controller/helpers.rb +151 -0
- data/lib/abstract_controller/layouts.rb +250 -0
- data/lib/abstract_controller/localized_cache.rb +49 -0
- data/lib/abstract_controller/logger.rb +61 -0
- data/lib/abstract_controller/rendering_controller.rb +188 -0
- data/lib/action_controller.rb +72 -0
- data/lib/action_controller/base.rb +168 -0
- data/lib/action_controller/caching.rb +80 -0
- data/lib/action_controller/caching/actions.rb +163 -0
- data/lib/action_controller/caching/fragments.rb +116 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/deprecated.rb +4 -0
- data/lib/action_controller/deprecated/integration_test.rb +2 -0
- data/lib/action_controller/deprecated/performance_test.rb +1 -0
- data/lib/action_controller/dispatch/dispatcher.rb +57 -0
- data/lib/action_controller/metal.rb +129 -0
- data/lib/action_controller/metal/benchmarking.rb +73 -0
- data/lib/action_controller/metal/compatibility.rb +145 -0
- data/lib/action_controller/metal/conditional_get.rb +86 -0
- data/lib/action_controller/metal/configuration.rb +28 -0
- data/lib/action_controller/metal/cookies.rb +105 -0
- data/lib/action_controller/metal/exceptions.rb +55 -0
- data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
- data/lib/action_controller/metal/flash.rb +162 -0
- data/lib/action_controller/metal/head.rb +27 -0
- data/lib/action_controller/metal/helpers.rb +115 -0
- data/lib/action_controller/metal/hide_actions.rb +47 -0
- data/lib/action_controller/metal/http_authentication.rb +312 -0
- data/lib/action_controller/metal/layouts.rb +171 -0
- data/lib/action_controller/metal/mime_responds.rb +317 -0
- data/lib/action_controller/metal/rack_convenience.rb +27 -0
- data/lib/action_controller/metal/redirector.rb +22 -0
- data/lib/action_controller/metal/render_options.rb +103 -0
- data/lib/action_controller/metal/rendering_controller.rb +57 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
- data/lib/action_controller/metal/rescuable.rb +13 -0
- data/lib/action_controller/metal/responder.rb +200 -0
- data/lib/action_controller/metal/session.rb +15 -0
- data/lib/action_controller/metal/session_management.rb +45 -0
- data/lib/action_controller/metal/streaming.rb +188 -0
- data/lib/action_controller/metal/testing.rb +39 -0
- data/lib/action_controller/metal/url_for.rb +41 -0
- data/lib/action_controller/metal/verification.rb +130 -0
- data/lib/action_controller/middleware.rb +38 -0
- data/lib/action_controller/notifications.rb +10 -0
- data/lib/action_controller/polymorphic_routes.rb +183 -0
- data/lib/action_controller/record_identifier.rb +91 -0
- data/lib/action_controller/testing/process.rb +111 -0
- data/lib/action_controller/testing/test_case.rb +345 -0
- data/lib/action_controller/translation.rb +13 -0
- data/lib/action_controller/url_rewriter.rb +204 -0
- data/lib/action_controller/vendor/html-scanner.rb +16 -0
- data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
- data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
- data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
- data/lib/action_dispatch.rb +70 -0
- data/lib/action_dispatch/http/headers.rb +33 -0
- data/lib/action_dispatch/http/mime_type.rb +231 -0
- data/lib/action_dispatch/http/mime_types.rb +23 -0
- data/lib/action_dispatch/http/request.rb +539 -0
- data/lib/action_dispatch/http/response.rb +290 -0
- data/lib/action_dispatch/http/status_codes.rb +42 -0
- data/lib/action_dispatch/http/utils.rb +20 -0
- data/lib/action_dispatch/middleware/callbacks.rb +50 -0
- data/lib/action_dispatch/middleware/params_parser.rb +79 -0
- data/lib/action_dispatch/middleware/rescue.rb +26 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
- data/lib/action_dispatch/middleware/stack.rb +116 -0
- data/lib/action_dispatch/middleware/static.rb +44 -0
- data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
- data/lib/action_dispatch/routing.rb +381 -0
- data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
- data/lib/action_dispatch/routing/mapper.rb +327 -0
- data/lib/action_dispatch/routing/route.rb +49 -0
- data/lib/action_dispatch/routing/route_set.rb +497 -0
- data/lib/action_dispatch/testing/assertions.rb +8 -0
- data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
- data/lib/action_dispatch/testing/assertions/model.rb +19 -0
- data/lib/action_dispatch/testing/assertions/response.rb +145 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
- data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
- data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
- data/lib/action_dispatch/testing/integration.rb +504 -0
- data/lib/action_dispatch/testing/performance_test.rb +15 -0
- data/lib/action_dispatch/testing/test_request.rb +83 -0
- data/lib/action_dispatch/testing/test_response.rb +131 -0
- data/lib/action_pack.rb +24 -0
- data/lib/action_pack/version.rb +9 -0
- data/lib/action_view.rb +58 -0
- data/lib/action_view/base.rb +308 -0
- data/lib/action_view/context.rb +44 -0
- data/lib/action_view/erb/util.rb +48 -0
- data/lib/action_view/helpers.rb +62 -0
- data/lib/action_view/helpers/active_model_helper.rb +306 -0
- data/lib/action_view/helpers/ajax_helper.rb +68 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
- data/lib/action_view/helpers/cache_helper.rb +39 -0
- data/lib/action_view/helpers/capture_helper.rb +168 -0
- data/lib/action_view/helpers/date_helper.rb +988 -0
- data/lib/action_view/helpers/debug_helper.rb +38 -0
- data/lib/action_view/helpers/form_helper.rb +1102 -0
- data/lib/action_view/helpers/form_options_helper.rb +600 -0
- data/lib/action_view/helpers/form_tag_helper.rb +495 -0
- data/lib/action_view/helpers/javascript_helper.rb +208 -0
- data/lib/action_view/helpers/number_helper.rb +311 -0
- data/lib/action_view/helpers/prototype_helper.rb +1309 -0
- data/lib/action_view/helpers/raw_output_helper.rb +9 -0
- data/lib/action_view/helpers/record_identification_helper.rb +20 -0
- data/lib/action_view/helpers/record_tag_helper.rb +58 -0
- data/lib/action_view/helpers/sanitize_helper.rb +259 -0
- data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
- data/lib/action_view/helpers/tag_helper.rb +151 -0
- data/lib/action_view/helpers/text_helper.rb +594 -0
- data/lib/action_view/helpers/translation_helper.rb +39 -0
- data/lib/action_view/helpers/url_helper.rb +639 -0
- data/lib/action_view/locale/en.yml +117 -0
- data/lib/action_view/paths.rb +80 -0
- data/lib/action_view/render/partials.rb +342 -0
- data/lib/action_view/render/rendering.rb +134 -0
- data/lib/action_view/safe_buffer.rb +28 -0
- data/lib/action_view/template/error.rb +101 -0
- data/lib/action_view/template/handler.rb +36 -0
- data/lib/action_view/template/handlers.rb +52 -0
- data/lib/action_view/template/handlers/builder.rb +17 -0
- data/lib/action_view/template/handlers/erb.rb +53 -0
- data/lib/action_view/template/handlers/rjs.rb +18 -0
- data/lib/action_view/template/resolver.rb +165 -0
- data/lib/action_view/template/template.rb +131 -0
- data/lib/action_view/template/text.rb +38 -0
- data/lib/action_view/test_case.rb +163 -0
- metadata +236 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
module ActionController
|
2
|
+
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
|
3
|
+
# repeated setups. The inclusion pattern has pages that look like this:
|
4
|
+
#
|
5
|
+
# <%= render "shared/header" %>
|
6
|
+
# Hello World
|
7
|
+
# <%= render "shared/footer" %>
|
8
|
+
#
|
9
|
+
# This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose
|
10
|
+
# and if you ever want to change the structure of these two includes, you'll have to change all the templates.
|
11
|
+
#
|
12
|
+
# With layouts, you can flip it around and have the common structure know where to insert changing content. This means
|
13
|
+
# that the header and footer are only mentioned in one place, like this:
|
14
|
+
#
|
15
|
+
# // The header part of this layout
|
16
|
+
# <%= yield %>
|
17
|
+
# // The footer part of this layout
|
18
|
+
#
|
19
|
+
# And then you have content pages that look like this:
|
20
|
+
#
|
21
|
+
# hello world
|
22
|
+
#
|
23
|
+
# At rendering time, the content page is computed and then inserted in the layout, like this:
|
24
|
+
#
|
25
|
+
# // The header part of this layout
|
26
|
+
# hello world
|
27
|
+
# // The footer part of this layout
|
28
|
+
#
|
29
|
+
# == Accessing shared variables
|
30
|
+
#
|
31
|
+
# Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with
|
32
|
+
# references that won't materialize before rendering time:
|
33
|
+
#
|
34
|
+
# <h1><%= @page_title %></h1>
|
35
|
+
# <%= yield %>
|
36
|
+
#
|
37
|
+
# ...and content pages that fulfill these references _at_ rendering time:
|
38
|
+
#
|
39
|
+
# <% @page_title = "Welcome" %>
|
40
|
+
# Off-world colonies offers you a chance to start a new life
|
41
|
+
#
|
42
|
+
# The result after rendering is:
|
43
|
+
#
|
44
|
+
# <h1>Welcome</h1>
|
45
|
+
# Off-world colonies offers you a chance to start a new life
|
46
|
+
#
|
47
|
+
# == Layout assignment
|
48
|
+
#
|
49
|
+
# You can either specify a layout declaratively (using the #layout class method) or give
|
50
|
+
# it the same name as your controller, and place it in <tt>app/views/layouts</tt>.
|
51
|
+
# If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance.
|
52
|
+
#
|
53
|
+
# For instance, if you have PostsController and a template named <tt>app/views/layouts/posts.html.erb</tt>,
|
54
|
+
# that template will be used for all actions in PostsController and controllers inheriting
|
55
|
+
# from PostsController.
|
56
|
+
#
|
57
|
+
# If you use a module, for instance Weblog::PostsController, you will need a template named
|
58
|
+
# <tt>app/views/layouts/weblog/posts.html.erb</tt>.
|
59
|
+
#
|
60
|
+
# Since all your controllers inherit from ApplicationController, they will use
|
61
|
+
# <tt>app/views/layouts/application.html.erb</tt> if no other layout is specified
|
62
|
+
# or provided.
|
63
|
+
#
|
64
|
+
# == Inheritance Examples
|
65
|
+
#
|
66
|
+
# class BankController < ActionController::Base
|
67
|
+
# layout "bank_standard"
|
68
|
+
#
|
69
|
+
# class InformationController < BankController
|
70
|
+
#
|
71
|
+
# class TellerController < BankController
|
72
|
+
# # teller.html.erb exists
|
73
|
+
#
|
74
|
+
# class TillController < TellerController
|
75
|
+
#
|
76
|
+
# class VaultController < BankController
|
77
|
+
# layout :access_level_layout
|
78
|
+
#
|
79
|
+
# class EmployeeController < BankController
|
80
|
+
# layout nil
|
81
|
+
#
|
82
|
+
# The InformationController uses "bank_standard" inherited from the BankController, the VaultController overwrites
|
83
|
+
# and picks the layout dynamically, and the EmployeeController doesn't want to use a layout at all.
|
84
|
+
#
|
85
|
+
# The TellerController uses +teller.html.erb+, and TillController inherits that layout and
|
86
|
+
# uses it as well.
|
87
|
+
#
|
88
|
+
# == Types of layouts
|
89
|
+
#
|
90
|
+
# Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes
|
91
|
+
# you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can
|
92
|
+
# be done either by specifying a method reference as a symbol or using an inline method (as a proc).
|
93
|
+
#
|
94
|
+
# The method reference is the preferred approach to variable layouts and is used like this:
|
95
|
+
#
|
96
|
+
# class WeblogController < ActionController::Base
|
97
|
+
# layout :writers_and_readers
|
98
|
+
#
|
99
|
+
# def index
|
100
|
+
# # fetching posts
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# private
|
104
|
+
# def writers_and_readers
|
105
|
+
# logged_in? ? "writer_layout" : "reader_layout"
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing
|
109
|
+
# is logged in or not.
|
110
|
+
#
|
111
|
+
# If you want to use an inline method, such as a proc, do something like this:
|
112
|
+
#
|
113
|
+
# class WeblogController < ActionController::Base
|
114
|
+
# layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }
|
115
|
+
#
|
116
|
+
# Of course, the most common way of specifying a layout is still just as a plain template name:
|
117
|
+
#
|
118
|
+
# class WeblogController < ActionController::Base
|
119
|
+
# layout "weblog_standard"
|
120
|
+
#
|
121
|
+
# If no directory is specified for the template name, the template will by default be looked for in <tt>app/views/layouts/</tt>.
|
122
|
+
# Otherwise, it will be looked up relative to the template root.
|
123
|
+
#
|
124
|
+
# == Conditional layouts
|
125
|
+
#
|
126
|
+
# If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering
|
127
|
+
# a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The
|
128
|
+
# <tt>:only</tt> and <tt>:except</tt> options can be passed to the layout call. For example:
|
129
|
+
#
|
130
|
+
# class WeblogController < ActionController::Base
|
131
|
+
# layout "weblog_standard", :except => :rss
|
132
|
+
#
|
133
|
+
# # ...
|
134
|
+
#
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout
|
138
|
+
# around the rendered view.
|
139
|
+
#
|
140
|
+
# Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
|
141
|
+
# #<tt>:except => [ :rss, :text_only ]</tt> is valid, as is <tt>:except => :rss</tt>.
|
142
|
+
#
|
143
|
+
# == Using a different layout in the action render call
|
144
|
+
#
|
145
|
+
# If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above.
|
146
|
+
# Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller.
|
147
|
+
# You can do this by passing a <tt>:layout</tt> option to the <tt>render</tt> call. For example:
|
148
|
+
#
|
149
|
+
# class WeblogController < ActionController::Base
|
150
|
+
# layout "weblog_standard"
|
151
|
+
#
|
152
|
+
# def help
|
153
|
+
# render :action => "help", :layout => "help"
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
|
158
|
+
module Layouts
|
159
|
+
extend ActiveSupport::Concern
|
160
|
+
|
161
|
+
include ActionController::RenderingController
|
162
|
+
include AbstractController::Layouts
|
163
|
+
|
164
|
+
module ClassMethods
|
165
|
+
# If no layout is provided, look for a layout with this name.
|
166
|
+
def _implied_layout_name
|
167
|
+
controller_path
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
module ActionController #:nodoc:
|
2
|
+
module MimeResponds #:nodoc:
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extlib_inheritable_accessor :responder, :mimes_for_respond_to, :instance_writer => false
|
7
|
+
self.responder = ActionController::Responder
|
8
|
+
clear_respond_to
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# Defines mimes that are rendered by default when invoking respond_with.
|
13
|
+
#
|
14
|
+
# Examples:
|
15
|
+
#
|
16
|
+
# respond_to :html, :xml, :json
|
17
|
+
#
|
18
|
+
# All actions on your controller will respond to :html, :xml and :json.
|
19
|
+
#
|
20
|
+
# But if you want to specify it based on your actions, you can use only and
|
21
|
+
# except:
|
22
|
+
#
|
23
|
+
# respond_to :html
|
24
|
+
# respond_to :xml, :json, :except => [ :edit ]
|
25
|
+
#
|
26
|
+
# The definition above explicits that all actions respond to :html. And all
|
27
|
+
# actions except :edit respond to :xml and :json.
|
28
|
+
#
|
29
|
+
# You can specify also only parameters:
|
30
|
+
#
|
31
|
+
# respond_to :rjs, :only => :create
|
32
|
+
#
|
33
|
+
def respond_to(*mimes)
|
34
|
+
options = mimes.extract_options!
|
35
|
+
|
36
|
+
only_actions = Array(options.delete(:only))
|
37
|
+
except_actions = Array(options.delete(:except))
|
38
|
+
|
39
|
+
mimes.each do |mime|
|
40
|
+
mime = mime.to_sym
|
41
|
+
mimes_for_respond_to[mime] = {}
|
42
|
+
mimes_for_respond_to[mime][:only] = only_actions unless only_actions.empty?
|
43
|
+
mimes_for_respond_to[mime][:except] = except_actions unless except_actions.empty?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Clear all mimes in respond_to.
|
48
|
+
#
|
49
|
+
def clear_respond_to
|
50
|
+
self.mimes_for_respond_to = ActiveSupport::OrderedHash.new
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Without web-service support, an action which collects the data for displaying a list of people
|
55
|
+
# might look something like this:
|
56
|
+
#
|
57
|
+
# def index
|
58
|
+
# @people = Person.find(:all)
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# Here's the same action, with web-service support baked in:
|
62
|
+
#
|
63
|
+
# def index
|
64
|
+
# @people = Person.find(:all)
|
65
|
+
#
|
66
|
+
# respond_to do |format|
|
67
|
+
# format.html
|
68
|
+
# format.xml { render :xml => @people.to_xml }
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# What that says is, "if the client wants HTML in response to this action, just respond as we
|
73
|
+
# would have before, but if the client wants XML, return them the list of people in XML format."
|
74
|
+
# (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
|
75
|
+
#
|
76
|
+
# Supposing you have an action that adds a new person, optionally creating their company
|
77
|
+
# (by name) if it does not already exist, without web-services, it might look like this:
|
78
|
+
#
|
79
|
+
# def create
|
80
|
+
# @company = Company.find_or_create_by_name(params[:company][:name])
|
81
|
+
# @person = @company.people.create(params[:person])
|
82
|
+
#
|
83
|
+
# redirect_to(person_list_url)
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# Here's the same action, with web-service support baked in:
|
87
|
+
#
|
88
|
+
# def create
|
89
|
+
# company = params[:person].delete(:company)
|
90
|
+
# @company = Company.find_or_create_by_name(company[:name])
|
91
|
+
# @person = @company.people.create(params[:person])
|
92
|
+
#
|
93
|
+
# respond_to do |format|
|
94
|
+
# format.html { redirect_to(person_list_url) }
|
95
|
+
# format.js
|
96
|
+
# format.xml { render :xml => @person.to_xml(:include => @company) }
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# If the client wants HTML, we just redirect them back to the person list. If they want Javascript
|
101
|
+
# (format.js), then it is an RJS request and we render the RJS template associated with this action.
|
102
|
+
# Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
|
103
|
+
# include the person's company in the rendered XML, so you get something like this:
|
104
|
+
#
|
105
|
+
# <person>
|
106
|
+
# <id>...</id>
|
107
|
+
# ...
|
108
|
+
# <company>
|
109
|
+
# <id>...</id>
|
110
|
+
# <name>...</name>
|
111
|
+
# ...
|
112
|
+
# </company>
|
113
|
+
# </person>
|
114
|
+
#
|
115
|
+
# Note, however, the extra bit at the top of that action:
|
116
|
+
#
|
117
|
+
# company = params[:person].delete(:company)
|
118
|
+
# @company = Company.find_or_create_by_name(company[:name])
|
119
|
+
#
|
120
|
+
# This is because the incoming XML document (if a web-service request is in process) can only contain a
|
121
|
+
# single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
|
122
|
+
#
|
123
|
+
# person[name]=...&person[company][name]=...&...
|
124
|
+
#
|
125
|
+
# And, like this (xml-encoded):
|
126
|
+
#
|
127
|
+
# <person>
|
128
|
+
# <name>...</name>
|
129
|
+
# <company>
|
130
|
+
# <name>...</name>
|
131
|
+
# </company>
|
132
|
+
# </person>
|
133
|
+
#
|
134
|
+
# In other words, we make the request so that it operates on a single entity's person. Then, in the action,
|
135
|
+
# we extract the company data from the request, find or create the company, and then create the new person
|
136
|
+
# with the remaining data.
|
137
|
+
#
|
138
|
+
# Note that you can define your own XML parameter parser which would allow you to describe multiple entities
|
139
|
+
# in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
|
140
|
+
# and accept Rails' defaults, life will be much easier.
|
141
|
+
#
|
142
|
+
# If you need to use a MIME type which isn't supported by default, you can register your own handlers in
|
143
|
+
# environment.rb as follows.
|
144
|
+
#
|
145
|
+
# Mime::Type.register "image/jpg", :jpg
|
146
|
+
#
|
147
|
+
# Respond to also allows you to specify a common block for different formats by using any:
|
148
|
+
#
|
149
|
+
# def index
|
150
|
+
# @people = Person.find(:all)
|
151
|
+
#
|
152
|
+
# respond_to do |format|
|
153
|
+
# format.html
|
154
|
+
# format.any(:xml, :json) { render request.format.to_sym => @people }
|
155
|
+
# end
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# In the example above, if the format is xml, it will render:
|
159
|
+
#
|
160
|
+
# render :xml => @people
|
161
|
+
#
|
162
|
+
# Or if the format is json:
|
163
|
+
#
|
164
|
+
# render :json => @people
|
165
|
+
#
|
166
|
+
# Since this is a common pattern, you can use the class method respond_to
|
167
|
+
# with the respond_with method to have the same results:
|
168
|
+
#
|
169
|
+
# class PeopleController < ApplicationController
|
170
|
+
# respond_to :html, :xml, :json
|
171
|
+
#
|
172
|
+
# def index
|
173
|
+
# @people = Person.find(:all)
|
174
|
+
# respond_with(@person)
|
175
|
+
# end
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
# Be sure to check respond_with and respond_to documentation for more examples.
|
179
|
+
#
|
180
|
+
def respond_to(*mimes, &block)
|
181
|
+
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
|
182
|
+
|
183
|
+
if response = retrieve_response_from_mimes(mimes, &block)
|
184
|
+
response.call
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# respond_with wraps a resource around a responder for default representation.
|
189
|
+
# First it invokes respond_to, if a response cannot be found (ie. no block
|
190
|
+
# for the request was given and template was not available), it instantiates
|
191
|
+
# an ActionController::Responder with the controller and resource.
|
192
|
+
#
|
193
|
+
# ==== Example
|
194
|
+
#
|
195
|
+
# def index
|
196
|
+
# @users = User.all
|
197
|
+
# respond_with(@users)
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# It also accepts a block to be given. It's used to overwrite a default
|
201
|
+
# response:
|
202
|
+
#
|
203
|
+
# def destroy
|
204
|
+
# @user = User.find(params[:id])
|
205
|
+
# flash[:notice] = "User was successfully created." if @user.save
|
206
|
+
#
|
207
|
+
# respond_with(@user) do |format|
|
208
|
+
# format.html { render }
|
209
|
+
# end
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
# All options given to respond_with are sent to the underlying responder,
|
213
|
+
# except for the option :responder itself. Since the responder interface
|
214
|
+
# is quite simple (it just needs to respond to call), you can even give
|
215
|
+
# a proc to it.
|
216
|
+
#
|
217
|
+
def respond_with(*resources, &block)
|
218
|
+
if response = retrieve_response_from_mimes([], &block)
|
219
|
+
options = resources.extract_options!
|
220
|
+
options.merge!(:default_response => response)
|
221
|
+
(options.delete(:responder) || responder).call(self, resources, options)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
protected
|
226
|
+
|
227
|
+
# Collect mimes declared in the class method respond_to valid for the
|
228
|
+
# current action.
|
229
|
+
#
|
230
|
+
def collect_mimes_from_class_level #:nodoc:
|
231
|
+
action = action_name.to_sym
|
232
|
+
|
233
|
+
mimes_for_respond_to.keys.select do |mime|
|
234
|
+
config = mimes_for_respond_to[mime]
|
235
|
+
|
236
|
+
if config[:except]
|
237
|
+
!config[:except].include?(action)
|
238
|
+
elsif config[:only]
|
239
|
+
config[:only].include?(action)
|
240
|
+
else
|
241
|
+
true
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Collects mimes and return the response for the negotiated format. Returns
|
247
|
+
# nil if :not_acceptable was sent to the client.
|
248
|
+
#
|
249
|
+
def retrieve_response_from_mimes(mimes, &block)
|
250
|
+
collector = Collector.new { default_render }
|
251
|
+
mimes = collect_mimes_from_class_level if mimes.empty?
|
252
|
+
mimes.each { |mime| collector.send(mime) }
|
253
|
+
block.call(collector) if block_given?
|
254
|
+
|
255
|
+
if format = request.negotiate_mime(collector.order)
|
256
|
+
self.formats = [format.to_sym]
|
257
|
+
collector.response_for(format)
|
258
|
+
else
|
259
|
+
head :not_acceptable
|
260
|
+
nil
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
class Collector #:nodoc:
|
265
|
+
attr_accessor :order
|
266
|
+
|
267
|
+
def initialize(&block)
|
268
|
+
@order, @responses, @default_response = [], {}, block
|
269
|
+
end
|
270
|
+
|
271
|
+
def any(*args, &block)
|
272
|
+
if args.any?
|
273
|
+
args.each { |type| send(type, &block) }
|
274
|
+
else
|
275
|
+
custom(Mime::ALL, &block)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
alias :all :any
|
279
|
+
|
280
|
+
def custom(mime_type, &block)
|
281
|
+
mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
|
282
|
+
@order << mime_type
|
283
|
+
@responses[mime_type] ||= block
|
284
|
+
end
|
285
|
+
|
286
|
+
def response_for(mime)
|
287
|
+
@responses[mime] || @responses[Mime::ALL] || @default_response
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.generate_method_for_mime(mime)
|
291
|
+
sym = mime.is_a?(Symbol) ? mime : mime.to_sym
|
292
|
+
const = sym.to_s.upcase
|
293
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
294
|
+
def #{sym}(&block) # def html(&block)
|
295
|
+
custom(Mime::#{const}, &block) # custom(Mime::HTML, &block)
|
296
|
+
end # end
|
297
|
+
RUBY
|
298
|
+
end
|
299
|
+
|
300
|
+
Mime::SET.each do |mime|
|
301
|
+
generate_method_for_mime(mime)
|
302
|
+
end
|
303
|
+
|
304
|
+
def method_missing(symbol, &block)
|
305
|
+
mime_constant = Mime.const_get(symbol.to_s.upcase)
|
306
|
+
|
307
|
+
if Mime::SET.include?(mime_constant)
|
308
|
+
self.class.generate_method_for_mime(mime_constant)
|
309
|
+
send(symbol, &block)
|
310
|
+
else
|
311
|
+
super
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|