Class: ActionView::Component::Base

Inherits:
Base
  • Object
show all
Includes:
ActionController::RequestForgeryProtection, ActiveModel::Validations, ActiveSupport::Configurable
Defined in:
lib/action_view/component/base.rb

Defined Under Namespace

Classes: DummyTemplate

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBase

Returns a new instance of Base.



82
# File 'lib/action_view/component/base.rb', line 82

def initialize(*); end

Class Method Details

.call_method_name(variant) ⇒ Object



131
132
133
134
135
136
137
# File 'lib/action_view/component/base.rb', line 131

def call_method_name(variant)
  if variant.present?
    "call_#{variant}"
  else
    "call"
  end
end

.compileObject

Compile templates to instance methods, assuming they haven’t been compiled already. We could in theory do this on app boot, at least in production environments. Right now this just compiles the first time the component is rendered.



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/action_view/component/base.rb', line 155

def compile
  return if @compiled && ActionView::Base.cache_template_loading

  validate_templates

  templates.each do |template|
    class_eval <<-RUBY, __FILE__, __LINE__ + 1
      def #{call_method_name(template[:variant])}
        @output_buffer = ActionView::OutputBuffer.new
        #{compiled_template(template[:path])}
      end
    RUBY
  end

  @compiled = true
end

.inherited(child) ⇒ Object



125
126
127
128
129
# File 'lib/action_view/component/base.rb', line 125

def inherited(child)
  child.include Rails.application.routes.url_helpers unless child < Rails.application.routes.url_helpers

  super
end

.source_locationObject

Raises:

  • (NotImplementedError)


139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/action_view/component/base.rb', line 139

def source_location
  # Require #initialize to be defined so that we can use
  # method#source_location to look up the file name
  # of the component.
  #
  # If we were able to only support Ruby 2.7+,
  # We could just use Module#const_source_location,
  # rendering this unnecessary.
  raise NotImplementedError.new("#{self} must implement #initialize.") unless self.instance_method(:initialize).owner == self

  instance_method(:initialize).source_location[0]
end

.variantsObject



172
173
174
# File 'lib/action_view/component/base.rb', line 172

def variants
  templates.map { |template| template[:variant] }
end

Instance Method Details

#controllerObject



92
93
94
# File 'lib/action_view/component/base.rb', line 92

def controller
  @controller ||= view_context.controller
end

#formatObject

:nodoc:



106
107
108
# File 'lib/action_view/component/base.rb', line 106

def format # :nodoc:
  @variant
end

#render(options = {}, args = {}, &block) ⇒ Object



84
85
86
87
88
89
90
# File 'lib/action_view/component/base.rb', line 84

def render(options = {}, args = {}, &block)
  if options.is_a?(String) || (options.is_a?(Hash) && options.has_key?(:partial))
    view_context.render(options, args, &block)
  else
    super
  end
end

#render_in(view_context, *args, &block) ⇒ Object

Entrypoint for rendering components. Called by ActionView::Base#render.

view_context: ActionView context from calling view args(hash): params to be passed to component being rendered block: optional block to be captured within the view context

returns HTML that has been escaped by the respective template handler

Example subclass:

app/components/my_component.rb: class MyComponent < ActionView::Component::Base

def initialize(title:)
  @title = title
end

end

app/components/my_component.html.erb <span title=“<%= @title %>”>Hello, <%= content %>!</span>

In use: <%= render MyComponent, title: “greeting” do %>world<% end %> returns: <span title=“greeting”>Hello, world!</span>



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/action_view/component/base.rb', line 63

def render_in(view_context, *args, &block)
  self.class.compile
  @view_context = view_context
  @view_renderer ||= view_context.view_renderer
  @lookup_context ||= view_context.lookup_context
  @view_flow ||= view_context.view_flow
  @virtual_path ||= virtual_path
  @variant = @lookup_context.variants.first
  old_current_template = @current_template
  @current_template = self

  @content = view_context.capture(&block) if block_given?
  validate!

  send(self.class.call_method_name(@variant))
ensure
  @current_template = old_current_template
end

#view_cache_dependenciesObject



102
103
104
# File 'lib/action_view/component/base.rb', line 102

def view_cache_dependencies
  []
end

#virtual_pathObject

Looks for the source file path of the initialize method of the instance’s class. Removes the first part of the path and the extension.



98
99
100
# File 'lib/action_view/component/base.rb', line 98

def virtual_path
  self.class.source_location.gsub(%r{(.*app/)|(\.rb)}, "")
end