extended_inherited_resources 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +25 -0
- data/LICENSE +20 -0
- data/README.rdoc +466 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/extended_inherited_resources.gemspec +70 -0
- data/init.rb +1 -0
- data/lib/inherited_resources.rb +43 -0
- data/lib/inherited_resources/actions.rb +67 -0
- data/lib/inherited_resources/base.rb +47 -0
- data/lib/inherited_resources/base_helpers.rb +284 -0
- data/lib/inherited_resources/belongs_to_helpers.rb +97 -0
- data/lib/inherited_resources/blank_slate.rb +12 -0
- data/lib/inherited_resources/class_methods.rb +281 -0
- data/lib/inherited_resources/dsl.rb +26 -0
- data/lib/inherited_resources/legacy/respond_to.rb +154 -0
- data/lib/inherited_resources/legacy/responder.rb +220 -0
- data/lib/inherited_resources/locales/en.yml +10 -0
- data/lib/inherited_resources/polymorphic_helpers.rb +155 -0
- data/lib/inherited_resources/responder.rb +6 -0
- data/lib/inherited_resources/singleton_helpers.rb +95 -0
- data/lib/inherited_resources/url_helpers.rb +182 -0
- data/lib/inherited_resources/version.rb +3 -0
- data/test/helper.rb +10 -0
- data/test/test_extended_inherited_resources.rb +7 -0
- metadata +101 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
module InheritedResources
|
2
|
+
|
3
|
+
# = belongs_to
|
4
|
+
#
|
5
|
+
# Let's suppose that we have some tasks that belongs to projects. To specify
|
6
|
+
# this assoication in your controllers, just do:
|
7
|
+
#
|
8
|
+
# class TasksController < InheritedResources::Base
|
9
|
+
# belongs_to :project
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# belongs_to accepts several options to be able to configure the association.
|
13
|
+
# For example, if you want urls like /projects/:project_title/tasks, you
|
14
|
+
# can customize how InheritedResources find your projects:
|
15
|
+
#
|
16
|
+
# class TasksController < InheritedResources::Base
|
17
|
+
# belongs_to :project, :finder => :find_by_title!, :param => :project_title
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# It also accepts :route_name, :parent_class and :instance_name as options.
|
21
|
+
# Check the lib/inherited_resources/class_methods.rb for more.
|
22
|
+
#
|
23
|
+
# = nested_belongs_to
|
24
|
+
#
|
25
|
+
# Now, our Tasks get some Comments and you need to nest even deeper. Good
|
26
|
+
# practices says that you should never nest more than two resources, but sometimes
|
27
|
+
# you have to for security reasons. So this is an example of how you can do it:
|
28
|
+
#
|
29
|
+
# class CommentsController < InheritedResources::Base
|
30
|
+
# nested_belongs_to :project, :task
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# If you need to configure any of these belongs to, you can nested them using blocks:
|
34
|
+
#
|
35
|
+
# class CommentsController < InheritedResources::Base
|
36
|
+
# belongs_to :project, :finder => :find_by_title!, :param => :project_title do
|
37
|
+
# belongs_to :task
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# Warning: calling several belongs_to is the same as nesting them:
|
42
|
+
#
|
43
|
+
# class CommentsController < InheritedResources::Base
|
44
|
+
# belongs_to :project
|
45
|
+
# belongs_to :task
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# In other words, the code above is the same as calling nested_belongs_to.
|
49
|
+
#
|
50
|
+
module BelongsToHelpers
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# Parent is always true when belongs_to is called.
|
55
|
+
#
|
56
|
+
def parent?
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def parent
|
61
|
+
@parent ||= association_chain[-1]
|
62
|
+
end
|
63
|
+
|
64
|
+
def parent_type
|
65
|
+
parent.class.name.underscore.to_sym
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# Evaluate the parent given. This is used to nest parents in the
|
71
|
+
# association chain.
|
72
|
+
#
|
73
|
+
def evaluate_parent(parent_symbol, parent_config, chain = nil) #:nodoc:
|
74
|
+
instantiated_object = instance_variable_get("@#{parent_config[:instance_name]}")
|
75
|
+
return instantiated_object if instantiated_object
|
76
|
+
|
77
|
+
parent = if chain
|
78
|
+
chain.send(parent_config[:collection_name])
|
79
|
+
else
|
80
|
+
parent_config[:parent_class]
|
81
|
+
end
|
82
|
+
|
83
|
+
parent = parent.send(parent_config[:finder], params[parent_config[:param]])
|
84
|
+
|
85
|
+
instance_variable_set("@#{parent_config[:instance_name]}", parent)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Maps parents_symbols to build association chain. In this case, it
|
89
|
+
# simply return the parent_symbols, however on polymorphic belongs to,
|
90
|
+
# it has some customization.
|
91
|
+
#
|
92
|
+
def symbols_for_association_chain #:nodoc:
|
93
|
+
parents_symbols
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
module InheritedResources
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
# Used to overwrite the default assumptions InheritedResources do. Whenever
|
7
|
+
# this method is called, it should be on the top of your controller, since
|
8
|
+
# almost other methods depends on the values given to <<tt>>defaults</tt>.
|
9
|
+
#
|
10
|
+
# == Options
|
11
|
+
#
|
12
|
+
# * <tt>:resource_class</tt> - The resource class which by default is guessed
|
13
|
+
# by the controller name. Defaults to Project in
|
14
|
+
# ProjectsController.
|
15
|
+
#
|
16
|
+
# * <tt>:collection_name</tt> - The name of the collection instance variable which
|
17
|
+
# is set on the index action. Defaults to :projects in
|
18
|
+
# ProjectsController.
|
19
|
+
#
|
20
|
+
# * <tt>:instance_name</tt> - The name of the singular instance variable which
|
21
|
+
# is set on all actions besides index action. Defaults to
|
22
|
+
# :project in ProjectsController.
|
23
|
+
#
|
24
|
+
# * <tt>:route_collection_name</tt> - The name of the collection route. Defaults to :collection_name.
|
25
|
+
#
|
26
|
+
# * <tt>:route_instance_name</tt> - The name of the singular route. Defaults to :instance_name.
|
27
|
+
#
|
28
|
+
# * <tt>:route_prefix</tt> - The route prefix which is automically set in namespaced
|
29
|
+
# controllers. Default to :admin on Admin::ProjectsController.
|
30
|
+
#
|
31
|
+
# * <tt>:singleton</tt> - Tells if this controller is singleton or not.
|
32
|
+
#
|
33
|
+
def defaults(options)
|
34
|
+
raise ArgumentError, 'Class method :defaults expects a hash of options.' unless options.is_a? Hash
|
35
|
+
|
36
|
+
options.symbolize_keys!
|
37
|
+
options.assert_valid_keys(:resource_class, :collection_name, :instance_name,
|
38
|
+
:class_name, :route_prefix, :route_collection_name,
|
39
|
+
:route_instance_name, :singleton, :redirects)
|
40
|
+
|
41
|
+
self.resource_class = options.delete(:resource_class) if options.key?(:resource_class)
|
42
|
+
self.resource_class = options.delete(:class_name).constantize if options.key?(:class_name)
|
43
|
+
|
44
|
+
acts_as_singleton! if options.delete(:singleton)
|
45
|
+
|
46
|
+
config = self.resources_configuration[:self]
|
47
|
+
config[:route_prefix] = options.delete(:route_prefix) if options.key?(:route_prefix)
|
48
|
+
|
49
|
+
#Add redirects configuration
|
50
|
+
self.redirects = options.delete(:redirects) || :index
|
51
|
+
|
52
|
+
if self.redirects.is_a? Hash
|
53
|
+
self.redirects[:create] ||= :index
|
54
|
+
self.redirects[:update] ||= :index
|
55
|
+
else
|
56
|
+
self.redirects = {:create => self.redirects, :update => self.redirects}
|
57
|
+
end
|
58
|
+
|
59
|
+
options.each do |key, value|
|
60
|
+
config[key] = value.to_sym
|
61
|
+
end
|
62
|
+
|
63
|
+
create_resources_url_helpers!
|
64
|
+
end
|
65
|
+
|
66
|
+
# Defines wich actions to keep from the inherited controller.
|
67
|
+
# Syntax is borrowed from resource_controller.
|
68
|
+
#
|
69
|
+
# actions :index, :show, :edit
|
70
|
+
# actions :all, :except => :index
|
71
|
+
#
|
72
|
+
def actions(*actions_to_keep)
|
73
|
+
raise ArgumentError, 'Wrong number of arguments. You have to provide which actions you want to keep.' if actions_to_keep.empty?
|
74
|
+
|
75
|
+
options = actions_to_keep.extract_options!
|
76
|
+
actions_to_remove = Array(options[:except])
|
77
|
+
actions_to_remove += ACTIONS - actions_to_keep.map { |a| a.to_sym } unless actions_to_keep.first == :all
|
78
|
+
actions_to_remove.map! { |a| a.to_sym }.uniq!
|
79
|
+
(instance_methods.map { |m| m.to_sym } & actions_to_remove).each do |action|
|
80
|
+
undef_method action, "#{action}!"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Defines that this controller belongs to another resource.
|
85
|
+
#
|
86
|
+
# belongs_to :projects
|
87
|
+
#
|
88
|
+
# == Options
|
89
|
+
#
|
90
|
+
# * <tt>:parent_class</tt> - Allows you to specify what is the parent class.
|
91
|
+
#
|
92
|
+
# belongs_to :project, :parent_class => AdminProject
|
93
|
+
#
|
94
|
+
# * <tt>:class_name</tt> - Also allows you to specify the parent class, but you should
|
95
|
+
# give a string. Added for ActiveRecord belongs to compatibility.
|
96
|
+
#
|
97
|
+
# * <tt>:instance_name</tt> - The instance variable name. By default is the name of the association.
|
98
|
+
#
|
99
|
+
# belongs_to :project, :instance_name => :my_project
|
100
|
+
#
|
101
|
+
# * <tt>:finder</tt> - Specifies which method should be called to instantiate the parent.
|
102
|
+
#
|
103
|
+
# belongs_to :project, :finder => :find_by_title!
|
104
|
+
#
|
105
|
+
# This will make your projects be instantiated as:
|
106
|
+
#
|
107
|
+
# Project.find_by_title!(params[:project_id])
|
108
|
+
#
|
109
|
+
# Instead of:
|
110
|
+
#
|
111
|
+
# Project.find(params[:project_id])
|
112
|
+
#
|
113
|
+
# * <tt>:param</tt> - Allows you to specify params key to retrieve the id.
|
114
|
+
# Default is :association_id, which in this case is :project_id.
|
115
|
+
#
|
116
|
+
# * <tt>:route_name</tt> - Allows you to specify what is the route name in your url
|
117
|
+
# helper. By default is association name.
|
118
|
+
#
|
119
|
+
# * <tt>:collection_name</tt> - Tell how to retrieve the next collection. Let's
|
120
|
+
# suppose you have Tasks which belongs to Projects
|
121
|
+
# which belongs to companies. This will do somewhere
|
122
|
+
# down the road:
|
123
|
+
#
|
124
|
+
# @company.projects
|
125
|
+
#
|
126
|
+
# But if you want to retrieve instead:
|
127
|
+
#
|
128
|
+
# @company.admin_projects
|
129
|
+
#
|
130
|
+
# You supply the collection name.
|
131
|
+
#
|
132
|
+
# * <tt>:polymorphic</tt> - Tell the association is polymorphic.
|
133
|
+
#
|
134
|
+
# * <tt>:singleton</tt> - Tell it's a singleton association.
|
135
|
+
#
|
136
|
+
# * <tt>:optional</tt> - Tell the association is optional (it's a special
|
137
|
+
# type of polymorphic association)
|
138
|
+
#
|
139
|
+
def belongs_to(*symbols, &block)
|
140
|
+
options = symbols.extract_options!
|
141
|
+
|
142
|
+
options.symbolize_keys!
|
143
|
+
options.assert_valid_keys(:class_name, :parent_class, :instance_name, :param,
|
144
|
+
:finder, :route_name, :collection_name, :singleton,
|
145
|
+
:polymorphic, :optional)
|
146
|
+
|
147
|
+
optional = options.delete(:optional)
|
148
|
+
singleton = options.delete(:singleton)
|
149
|
+
polymorphic = options.delete(:polymorphic)
|
150
|
+
finder = options.delete(:finder)
|
151
|
+
|
152
|
+
include BelongsToHelpers if self.parents_symbols.empty?
|
153
|
+
|
154
|
+
acts_as_singleton! if singleton
|
155
|
+
acts_as_polymorphic! if polymorphic || optional
|
156
|
+
|
157
|
+
raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty?
|
158
|
+
raise ArgumentError, 'You cannot define multiple associations with options: #{options.keys.inspect} to belongs to.' unless symbols.size == 1 || options.empty?
|
159
|
+
|
160
|
+
symbols.each do |symbol|
|
161
|
+
symbol = symbol.to_sym
|
162
|
+
|
163
|
+
if polymorphic || optional
|
164
|
+
self.parents_symbols << :polymorphic unless self.parents_symbols.include?(:polymorphic)
|
165
|
+
self.resources_configuration[:polymorphic][:symbols] << symbol
|
166
|
+
self.resources_configuration[:polymorphic][:optional] ||= optional
|
167
|
+
else
|
168
|
+
self.parents_symbols << symbol
|
169
|
+
end
|
170
|
+
|
171
|
+
config = self.resources_configuration[symbol] = {}
|
172
|
+
|
173
|
+
config[:parent_class] = options.delete(:parent_class) || begin
|
174
|
+
class_name = (options.delete(:class_name) || symbol).to_s.pluralize.classify
|
175
|
+
class_name.constantize
|
176
|
+
rescue NameError => e
|
177
|
+
raise unless e.message.include?(class_name)
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
|
181
|
+
config[:collection_name] = options.delete(:collection_name) || symbol.to_s.pluralize.to_sym
|
182
|
+
config[:instance_name] = options.delete(:instance_name) || symbol
|
183
|
+
config[:param] = options.delete(:param) || :"#{symbol}_id"
|
184
|
+
config[:route_name] = options.delete(:route_name) || symbol
|
185
|
+
config[:finder] = finder || :find
|
186
|
+
end
|
187
|
+
|
188
|
+
if block_given?
|
189
|
+
class_eval(&block)
|
190
|
+
else
|
191
|
+
create_resources_url_helpers!
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
alias :nested_belongs_to :belongs_to
|
196
|
+
|
197
|
+
# A quick method to declare polymorphic belongs to.
|
198
|
+
#
|
199
|
+
def polymorphic_belongs_to(*symbols, &block)
|
200
|
+
options = symbols.extract_options!
|
201
|
+
options.merge!(:polymorphic => true)
|
202
|
+
belongs_to(*symbols << options, &block)
|
203
|
+
end
|
204
|
+
|
205
|
+
# A quick method to declare singleton belongs to.
|
206
|
+
#
|
207
|
+
def singleton_belongs_to(*symbols, &block)
|
208
|
+
options = symbols.extract_options!
|
209
|
+
options.merge!(:singleton => true)
|
210
|
+
belongs_to(*symbols << options, &block)
|
211
|
+
end
|
212
|
+
|
213
|
+
# A quick method to declare optional belongs to.
|
214
|
+
#
|
215
|
+
def optional_belongs_to(*symbols, &block)
|
216
|
+
options = symbols.extract_options!
|
217
|
+
options.merge!(:optional => true)
|
218
|
+
belongs_to(*symbols << options, &block)
|
219
|
+
end
|
220
|
+
|
221
|
+
private
|
222
|
+
|
223
|
+
def acts_as_singleton! #:nodoc:
|
224
|
+
unless self.resources_configuration[:self][:singleton]
|
225
|
+
self.resources_configuration[:self][:singleton] = true
|
226
|
+
include SingletonHelpers
|
227
|
+
actions :all, :except => :index
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def acts_as_polymorphic! #:nodoc:
|
232
|
+
unless self.parents_symbols.include?(:polymorphic)
|
233
|
+
include PolymorphicHelpers
|
234
|
+
helper_method :parent, :parent_type, :parent_class, :parent?
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Initialize resources class accessors and set their default values.
|
239
|
+
#
|
240
|
+
def initialize_resources_class_accessors! #:nodoc:
|
241
|
+
# Initialize resource class
|
242
|
+
self.resource_class = begin
|
243
|
+
class_name = self.controller_name.classify
|
244
|
+
class_name.constantize
|
245
|
+
rescue NameError => e
|
246
|
+
raise unless e.message.include?(class_name)
|
247
|
+
nil
|
248
|
+
end
|
249
|
+
|
250
|
+
# Initialize resources configuration hash
|
251
|
+
self.resources_configuration ||= {}
|
252
|
+
config = self.resources_configuration[:self] = {}
|
253
|
+
config[:collection_name] = self.controller_name.to_sym
|
254
|
+
config[:instance_name] = self.controller_name.singularize.to_sym
|
255
|
+
|
256
|
+
config[:route_collection_name] = config[:collection_name]
|
257
|
+
config[:route_instance_name] = config[:instance_name]
|
258
|
+
|
259
|
+
# Deal with namespaced controllers
|
260
|
+
namespaces = self.controller_path.split('/')[0..-2]
|
261
|
+
config[:route_prefix] = namespaces.join('_') unless namespaces.empty?
|
262
|
+
|
263
|
+
self.redirects ||= {}
|
264
|
+
self.redirects[:create] ||= :index
|
265
|
+
self.redirects[:update] ||= :index
|
266
|
+
|
267
|
+
# Initialize polymorphic, singleton, scopes and belongs_to parameters
|
268
|
+
self.parents_symbols ||= []
|
269
|
+
self.resources_configuration[:polymorphic] ||= { :symbols => [], :optional => false }
|
270
|
+
end
|
271
|
+
|
272
|
+
# Hook called on inheritance.
|
273
|
+
#
|
274
|
+
def inherited(base) #:nodoc:
|
275
|
+
super(base)
|
276
|
+
base.send :initialize_resources_class_accessors!
|
277
|
+
base.send :create_resources_url_helpers!
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module InheritedResources
|
2
|
+
# Allows controllers to write actions using a class method DSL.
|
3
|
+
#
|
4
|
+
# class MyController < InheritedResources::Base
|
5
|
+
# create! do |success, failure|
|
6
|
+
# success.html { render :text => "It works!" }
|
7
|
+
# end
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
module DSL
|
11
|
+
def self.included(base)
|
12
|
+
ACTIONS.each do |action|
|
13
|
+
base.class_eval <<-WRITTER
|
14
|
+
def self.#{action}!(options={}, &block)
|
15
|
+
define_method :__#{action}, &block
|
16
|
+
class_eval <<-ACTION
|
17
|
+
def #{action}
|
18
|
+
super(\#{options.inspect}, &method(:__#{action}))
|
19
|
+
end
|
20
|
+
ACTION
|
21
|
+
end
|
22
|
+
WRITTER
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module ActionController #:nodoc:
|
2
|
+
class Base #:nodoc:
|
3
|
+
attr_accessor :formats
|
4
|
+
|
5
|
+
class_inheritable_accessor :mimes_for_respond_to, :responder, :instance_writer => false
|
6
|
+
|
7
|
+
self.responder = ActionController::Responder
|
8
|
+
self.mimes_for_respond_to = ActiveSupport::OrderedHash.new
|
9
|
+
|
10
|
+
if defined?(ApplicationController)
|
11
|
+
ApplicationController.responder ||= ActionController::Responder
|
12
|
+
ApplicationController.mimes_for_respond_to ||= ActiveSupport::OrderedHash.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# Defines mimes that are rendered by default when invoking respond_with.
|
16
|
+
#
|
17
|
+
# Examples:
|
18
|
+
#
|
19
|
+
# respond_to :html, :xml, :json
|
20
|
+
#
|
21
|
+
# All actions on your controller will respond to :html, :xml and :json.
|
22
|
+
#
|
23
|
+
# But if you want to specify it based on your actions, you can use only and
|
24
|
+
# except:
|
25
|
+
#
|
26
|
+
# respond_to :html
|
27
|
+
# respond_to :xml, :json, :except => [ :edit ]
|
28
|
+
#
|
29
|
+
# The definition above explicits that all actions respond to :html. And all
|
30
|
+
# actions except :edit respond to :xml and :json.
|
31
|
+
#
|
32
|
+
# You can specify also only parameters:
|
33
|
+
#
|
34
|
+
# respond_to :rjs, :only => :create
|
35
|
+
#
|
36
|
+
def self.respond_to(*mimes)
|
37
|
+
options = mimes.extract_options!
|
38
|
+
clear_respond_to unless mimes_for_respond_to
|
39
|
+
|
40
|
+
only_actions = Array(options.delete(:only))
|
41
|
+
except_actions = Array(options.delete(:except))
|
42
|
+
|
43
|
+
mimes.each do |mime|
|
44
|
+
mime = mime.to_sym
|
45
|
+
mimes_for_respond_to[mime] = {}
|
46
|
+
mimes_for_respond_to[mime][:only] = only_actions unless only_actions.empty?
|
47
|
+
mimes_for_respond_to[mime][:except] = except_actions unless except_actions.empty?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Clear all mimes in respond_to.
|
52
|
+
def self.clear_respond_to
|
53
|
+
write_inheritable_attribute(:mimes_for_respond_to, ActiveSupport::OrderedHash.new)
|
54
|
+
end
|
55
|
+
|
56
|
+
def respond_to(*mimes, &block)
|
57
|
+
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
|
58
|
+
if response = retrieve_response_from_mimes(mimes, &block)
|
59
|
+
response.call
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def respond_with(*resources, &block)
|
64
|
+
if response = retrieve_response_from_mimes([], &block)
|
65
|
+
options = resources.extract_options!
|
66
|
+
options.merge!(:default_response => response)
|
67
|
+
(options.delete(:responder) || responder).call(self, resources, options)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
# Collect mimes declared in the class method respond_to valid for the
|
74
|
+
# current action.
|
75
|
+
#
|
76
|
+
def collect_mimes_from_class_level #:nodoc:
|
77
|
+
action = action_name.to_sym
|
78
|
+
|
79
|
+
mimes_for_respond_to.keys.select do |mime|
|
80
|
+
config = mimes_for_respond_to[mime]
|
81
|
+
|
82
|
+
if config[:except]
|
83
|
+
!config[:except].include?(action)
|
84
|
+
elsif config[:only]
|
85
|
+
config[:only].include?(action)
|
86
|
+
else
|
87
|
+
true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Collects mimes and return the response for the negotiated format. Returns
|
93
|
+
# nil if :not_acceptable was sent to the client.
|
94
|
+
#
|
95
|
+
def retrieve_response_from_mimes(mimes, &block)
|
96
|
+
responder = ActionController::MimeResponds::Responder.new(self)
|
97
|
+
mimes = collect_mimes_from_class_level if mimes.empty?
|
98
|
+
mimes.each { |mime| responder.send(mime) }
|
99
|
+
block.call(responder) if block_given?
|
100
|
+
|
101
|
+
if format = responder.negotiate_mime
|
102
|
+
self.response.template.template_format = format.to_sym
|
103
|
+
self.response.content_type = format.to_s
|
104
|
+
self.formats = [ format.to_sym ]
|
105
|
+
responder.response_for(format) || proc { default_render }
|
106
|
+
else
|
107
|
+
head :not_acceptable
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
module MimeResponds
|
114
|
+
class Responder #:nodoc:
|
115
|
+
attr_reader :order
|
116
|
+
|
117
|
+
def any(*args, &block)
|
118
|
+
if args.any?
|
119
|
+
args.each { |type| send(type, &block) }
|
120
|
+
else
|
121
|
+
custom(Mime::ALL, &block)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
alias :all :any
|
125
|
+
|
126
|
+
def custom(mime_type, &block)
|
127
|
+
mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
|
128
|
+
@order << mime_type
|
129
|
+
@responses[mime_type] ||= block
|
130
|
+
end
|
131
|
+
|
132
|
+
def response_for(mime)
|
133
|
+
@responses[mime] || @responses[Mime::ALL]
|
134
|
+
end
|
135
|
+
|
136
|
+
def negotiate_mime
|
137
|
+
@mime_type_priority.each do |priority|
|
138
|
+
if priority == Mime::ALL
|
139
|
+
return @order.first
|
140
|
+
elsif @order.include?(priority)
|
141
|
+
return priority
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
if @order.include?(Mime::ALL)
|
146
|
+
return Mime::SET.first if @mime_type_priority.first == Mime::ALL
|
147
|
+
return @mime_type_priority.first
|
148
|
+
end
|
149
|
+
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|