Class: Merb::AbstractController

Inherits:
Object
  • Object
show all
Includes:
InlineTemplates, RenderMixin
Defined in:
merb-core/lib/merb-core/controller/abstract_controller.rb,
merb-action-args/lib/merb-action-args/abstract_controller.rb,
merb-helpers/lib/merb-helpers/form_helpers.rb

Direct Known Subclasses

Controller, MailController

Constant Summary

FILTER_OPTIONS =
[:only, :exclude, :if, :unless, :with]

Constants included from ControllerExceptions

ControllerExceptions::STATUS_CODES

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from RenderMixin

#_get_layout, #_handle_options!, #_template_for, #_template_method_for, #append_content, #catch_content, #clear_content, #display, included, #partial, #render, #throw_content, #thrown_content?

Constructor Details

#initialize(*args) ⇒ AbstractController

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize the controller.

This is designed to be overridden in subclasses like Controller

Parameters:

  • *args

    The args are ignored in this class, but we need this so that subclassed initializes can have parameters



250
251
252
253
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 250

def initialize(*args)
  @_benchmarks = {}
  @_caught_content = {}
end

Class Attribute Details

.action_argument_listObject

Returns the value of attribute action_argument_list



4
5
6
# File 'merb-action-args/lib/merb-action-args/abstract_controller.rb', line 4

def action_argument_list
  @action_argument_list
end

Instance Attribute Details

#_benchmarksObject



109
110
111
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 109

def _benchmarks
  @_benchmarks
end

#_thrown_contentObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



111
112
113
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 111

def _thrown_content
  @_thrown_content
end

#action_nameObject



109
110
111
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 109

def action_name
  @action_name
end

#bodyObject



109
110
111
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 109

def body
  @body
end

#content_typeObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Stub so content-type support in RenderMixin doesn't throw errors



115
116
117
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 115

def content_type
  @content_type
end

Class Method Details

._reset_template_rootsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Reset the template root based on the @_template_root ivar.



197
198
199
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 197

def self._reset_template_roots
  self.template_roots = [[self._template_root, :_template_location]]
end

._template_root=(root) ⇒ Object

Change the template roots.

Parameters:

  • root (#to_s)

    The new path to set the template root to.



189
190
191
192
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 189

def self._template_root=(root)
  @_template_root = root
  _reset_template_roots
end

._template_rootsArray<Array>

Returns Template roots as pairs of template root path and template location method.

Returns:

  • (Array<Array>)

    Template roots as pairs of template root path and template location method.



205
206
207
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 205

def self._template_roots
  self.template_roots || _reset_template_roots
end

._template_roots=(roots) ⇒ Object

Parameters:

  • roots (Array<Array>)

    Template roots as pairs of template root path and template location method.



213
214
215
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 213

def self._template_roots=(roots)
  self.template_roots = roots
end

.after(filter = nil, opts = {}, &block) ⇒ Object

Adds a filter to the after filter chain.

Notes

If the filter already exists, its options will be replaced with opts.

Parameters:

  • filter (Symbol, Proc) (defaults to: nil)

    The filter to add.

  • opts (Hash) (defaults to: {})

    Filter options (see class documentation under Filter Options).

  • &block

    A block to use as a filter if filter is nil.



425
426
427
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 425

def self.after(filter = nil, opts = {}, &block)
  add_filter(self._after_filters, filter || block, opts)
end

.before(filter = nil, opts = {}, &block) ⇒ Object

Adds a filter to the before filter chain.

(see AbstractController#after)



434
435
436
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 434

def self.before(filter = nil, opts = {}, &block)
  add_filter(self._before_filters, filter || block, opts)
end

.controller_nameString

Returns The controller name in path form, e.g. "admin/items".

Returns:

  • (String)

    The controller name in path form, e.g. "admin/items".



130
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 130

def self.controller_name() @controller_name ||= self.name.to_const_path end

.inherited(klass) ⇒ Object

Stores the argument lists for all methods for this class.

Parameters:



229
230
231
232
233
234
235
236
237
238
239
240
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 229

def self.inherited(klass)
  _abstract_subclasses << klass.to_s
  helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper"
  # support for unnamed module like "#<Class:0xa2e5e50>::TestController"
  helper_module_name.gsub!(/(::)|[:#<>]/, "\\1")

  Object.make_module helper_module_name
  klass.class_eval <<-HERE
    include Object.full_const_get("#{helper_module_name}") rescue nil
  HERE
  super
end

.old_inheritedObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:



5
6
7
8
9
10
11
12
13
14
15
16
# File 'merb-action-args/lib/merb-action-args/abstract_controller.rb', line 5

def self.inherited(klass)
  _abstract_subclasses << klass.to_s
  helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper"
  # support for unnamed module like "#<Class:0xa2e5e50>::TestController"
  helper_module_name.gsub!(/(::)|[:#<>]/, "\\1")

  Object.make_module helper_module_name
  klass.class_eval <<-HERE
    include Object.full_const_get("#{helper_module_name}") rescue nil
  HERE
  super
end

.skip_after(filter) ⇒ Object

Removes a filter from the after filter chain. This removes the filter from the filter chain for the whole controller and does not take any options.

Parameters:

  • filter (Symbol, String)

    A filter name to skip.



445
446
447
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 445

def self.skip_after(filter)
  skip_filter(self._after_filters, filter)
end

.skip_before(filter) ⇒ Object

Removes a filter from the before filter chain.

(see AbstractController#skip_after)



454
455
456
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 454

def self.skip_before(filter)
  skip_filter(self._before_filters , filter)
end

.subclasses_listSet

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the list of classes that have specifically subclassed AbstractController. Does not include all decendents.

Returns:

  • (Set)

    The subclasses.



223
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 223

def self.subclasses_list() _abstract_subclasses end

Instance Method Details

#_absolute_template_location(template, type) ⇒ Object

The location to look for a template.

Override this method for particular behaviour.

Parameters:

  • template (String)

    The absolute path to a template, without template extension.

  • type (#to_s)

    The mime-type of the template that will be rendered. Defaults to being called with nil.

Overridable:



180
181
182
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 180

def _absolute_template_location(template, type)
  template
end

#_call_action(action) ⇒ Object

Calls an action and maps the params hash to the action parameters.

Parameters:

  • action (Symbol)

    The action to call.

Raises:

  • (BadRequest)

    The params hash doesn't have a required parameter.



312
313
314
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 312

def _call_action(action)
  send(action)
end

#_call_filter_for_action?(rule, action_name) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Determine whether the filter should be called for the current action using :only and :exclude.

Parameters:

  • rule (Hash)

    Rules for the filter.

  • action_name (#to_s)

    The name of the action to be called.

Options Hash (rule):

  • :only (Array)

    Optional list of actions to fire. If given, action_name must be a part of it for this function to return true.

  • :exclude (Array)

    Optional list of actions not to fire. If given, action_name must not be a part of it for this function to return true.

Returns:

  • (Boolean)

    True if the action should be called.



364
365
366
367
368
369
370
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 364

def _call_filter_for_action?(rule, action_name)
  # Both:
  # * no :only or the current action is in the :only list
  # * no :exclude or the current action is not in the :exclude list
  (!rule.key?(:only) || rule[:only].include?(action_name)) &&
  (!rule.key?(:exclude) || !rule[:exclude].include?(action_name))
end

#_call_filters(filter_set) ⇒ Symbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Calls a filter chain.

Notes

Filter rules can be Symbols, Strings, or Procs.

  • Symbols or Strings: Call the method represented by the Symbol or String.
  • Procs: Execute the Proc, in the context of the controller (self will be the controller)

Parameters:

  • filter_set (Array<Filter>)

    A set of filters in the form [[:filter, rule], [:filter, rule]]

Returns:

  • (Symbol)

    :filter_chain_completed.



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 333

def _call_filters(filter_set)
  (filter_set || []).each do |filter, rule|
    if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule)
      case filter
      when Symbol, String
        if rule.key?(:with)
          args = rule[:with]
          send(filter, *args)
        else
          send(filter)
        end
      when Proc then self.instance_eval(&filter)
      end
    end
  end
  return :filter_chain_completed
end

#_dispatch(action) ⇒ #to_s

TODO:

Docs, correctness: It seems that the return value is never used, and Controller#_dispatch violates the contract by returning self. So for now, avoid using the return value. See ticket #1335.

Dispatch the request, calling internal before/after dispatch callbacks.

If the return value of _call_filters is not :filter_chain_completed, the action is not called, and the return from the filters is used instead.

Parameters:

  • action (#to_s)

    The action to dispatch to. This will be #send'ed in _call_action. Defaults to :to_s.

Returns:

  • (#to_s)

    The string, or an object that responds to #to_s, that was returned from the action.

Raises:

  • (ArgumentError)

    Invalid result caught from before filters.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 273

def _dispatch(action)
  self.action_name = action
  self._before_dispatch_callbacks.each { |cb| cb.call(self) }

  caught = catch(:halt) do
    start = Time.now
    result = _call_filters(_before_filters)
    @_benchmarks[:before_filters_time] = Time.now - start if _before_filters

    @body = _call_action(action_name) if result == :filter_chain_completed

    result
  end
  
  @body = case caught
  when :filter_chain_completed  then @body
  when String                   then caught
  # return *something* if you throw halt with nothing
  when nil                      then "<html><body><h1>Filter Chain Halted!</h1></body></html>"
  when Symbol                   then __send__(caught)
  when Proc                     then self.instance_eval(&caught)
  else
    raise ArgumentError, "Threw :halt, #{caught}. Expected String, nil, Symbol, Proc."
  end
  start = Time.now
  _call_filters(_after_filters)
  @_benchmarks[:after_filters_time] = Time.now - start if _after_filters

  self._after_dispatch_callbacks.each { |cb| cb.call(self) }

  @body
end

#_evaluate_condition(condition) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Evaluates a filter condition (:if or :unless)

Alternatives

If condition is a symbol, it will be send'ed. If it is a Proc it will be called directly with self as an argument.

Parameters:

  • condition (Symbol, Proc)

    The condition to evaluate.

Returns:

  • (Boolean)

    True if the condition is met.

Raises:

  • (ArgumentError)

    Condition not a Symbol or Proc.



404
405
406
407
408
409
410
411
412
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 404

def _evaluate_condition(condition)
  case condition
  when Symbol then self.send(condition)
  when Proc then self.instance_eval(&condition)
  else
    raise ArgumentError,
          'Filter condtions need to be either a Symbol or a Proc'
  end
end

#_filter_condition_met?(rule) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Determines whether the filter should be run based on the conditions passed (:if and :unless)

Parameters:

  • rule (Hash)

    Rules for the filter.

Options Hash (rule):

  • :if (Array)

    Optional conditions that must be met for the filter to fire.

  • :unless (Array)

    Optional conditions that must not be met for the filter to fire.

Returns:

  • (Boolean)

    True if the conditions are met.



383
384
385
386
387
388
389
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 383

def _filter_condition_met?(rule)
  # Both:
  # * no :if or the if condition evaluates to true
  # * no :unless or the unless condition evaluates to false
  (!rule.key?(:if) || _evaluate_condition(rule[:if])) &&
  (!rule.key?(:unless) || ! _evaluate_condition(rule[:unless]))
end

#_template_location(context, type, controller) ⇒ String

TODO:

"Set t" what?

Figure out where to look for templates under the _template_root after instantiating the controller. Override this to define a new structure for your app.

Notes

The type is irrelevant for controller-types that don't support content-type negotiation, so we default to not include it in the superclass.

Examples:

Modifying the template location

# This would look for templates at controller.action.mime.type instead
# of controller/action.mime.type

def _template_location
  "#{params[:controller]}.#{params[:action]}.#{content_type}"
end

Parameters:

  • context (#to_s)

    The controller context (action or template name).

  • type (#to_s)

    The content type. Could be nil.

  • controller (#to_s)

    The name of the controller. Defaults to being called with the controller_name. Set t

Returns:

  • (String)

    Indicating where to look for the template for the current controller, context, and content-type.

Overridable:



165
166
167
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 165

def _template_location(context, type, controller)
  controller ? "#{controller}/#{context}" : context
end

#absolute_url(*args) ⇒ Object

Returns the absolute URL including the passed protocol and host.

This uses the same arguments as the #url method, with added requirements of protocol and host options.

Raises:

  • (ArgumentError)


476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 476

def absolute_url(*args)
  # FIXME: arrgh, why request.protocol returns http://?
  # :// is not part of protocol name
  options  = extract_options_from_args!(args) || {}
  protocol = options.delete(:protocol)
  host     = options.delete(:host)

  raise ArgumentError, "The :protocol option must be specified" unless protocol
  raise ArgumentError, "The :host option must be specified"     unless host

  args << options

  protocol + "://" + host + url(*args)
end

#capture(*args, &block) ⇒ String

Calls the capture method for the selected template engine.

Parameters:

  • *args

    Arguments to pass to the block.

  • &block

    The block to call.

Returns:

  • (String)

    The output of a template block or the return value of a non-template block converted to a string.



510
511
512
513
514
515
516
517
518
519
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 510

def capture(*args, &block)
  ret = nil

  captured = send("capture_#{@_engine}", *args) do |*args|
    ret = yield *args
  end

  # return captured value only if it is not empty
  captured.empty? ? ret.to_s : captured
end

#concat(str, binding) ⇒ Object

Calls the concatenate method for the selected template engine.

Parameters:

  • str (String)

    The string to concatenate to the buffer.

  • binding (Binding)

    The binding to use for the buffer.



527
528
529
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 527

def concat(str, binding)
  send("concat_#{@_engine}", str, binding)
end

#controller_nameString

Returns The controller name in path form, e.g. "admin/items".

Returns:

  • (String)

    The controller name in path form, e.g. "admin/items".



135
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 135

def controller_name()      self.class.controller_name                   end

#resource(*args) ⇒ Object

Generates a URL for a single or nested resource.

See Also:



496
497
498
499
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 496

def resource(*args)
  args << {}
  Merb::Router.resource(*args)
end

#url(name, *args) ⇒ Object Also known as: relative_url

Generate URLs.

See Also:



463
464
465
466
# File 'merb-core/lib/merb-core/controller/abstract_controller.rb', line 463

def url(name, *args)
  args << {}
  Merb::Router.url(name, *args)
end