aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller/abstract/base.rb
blob: ab9aed0b26af63494a4e2df82a3e241e18d9efda (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
module AbstractController
  class Base
    
    attr_internal :response_body
    attr_internal :response_obj
    attr_internal :action_name

    class << self
      attr_reader :abstract    
      
      def abstract!
        @abstract = true
      end
      
      alias_method :abstract?, :abstract
      
      def internal_methods
        controller = self
        controller = controller.superclass until controller.abstract?
        controller.public_instance_methods(true)
      end
      
      def process(action)
        new.process(action.to_s)
      end

      def hidden_actions
        []
      end
      
      def action_methods
        @action_methods ||=
          # All public instance methods of this class, including ancestors
          public_instance_methods(true).map { |m| m.to_s }.to_set -
          # Except for public instance methods of Base and its ancestors
          internal_methods.map { |m| m.to_s } +
          # Be sure to include shadowed public instance methods of this class
          public_instance_methods(false).map { |m| m.to_s } -
          # And always exclude explicitly hidden actions
          hidden_actions
      end
    end
    
    abstract!
    
    def initialize
      self.response_obj = {}
    end
    
    def process(action_name)
      unless respond_to_action?(action_name)
        raise ActionNotFound, "The action '#{action_name}' could not be found"
      end
      
      @_action_name = action_name
      process_action
      self
    end
    
  private
  
    def action_methods
      self.class.action_methods
    end
  
    # It is possible for respond_to?(action_name) to be false and
    # respond_to?(:action_missing) to be false if respond_to_action?
    # is overridden in a subclass. For instance, ActionController::Base
    # overrides it to include the case where a template matching the
    # action_name is found.
    def process_action
      if respond_to?(action_name) then send(action_name)
      elsif respond_to?(:action_missing, true) then action_missing(action_name)
      end
    end
    
    # Override this to change the conditions that will raise an
    # ActionNotFound error. If you accept a difference case,
    # you must handle it by also overriding process_action and
    # handling the case.
    def respond_to_action?(action_name)
      action_methods.include?(action_name) || respond_to?(:action_missing, true)
    end
  end
end