Class: ActionView::Component::Base

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBase

Returns a new instance of Base.



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

def initialize(*); end

Class Method Details

.call_method_name(variant) ⇒ Object



105
106
107
108
109
110
111
# File 'lib/action_view/component/base.rb', line 105

def call_method_name(variant)
  if variant.present? && variants.include?(variant)
    "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.



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

def compile
  return if compiled?

  validate_templates

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

.compiled?Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/action_view/component/base.rb', line 130

def compiled?
  @compiled && ActionView::Base.cache_template_loading
end

.has_initializer?Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/action_view/component/base.rb', line 113

def has_initializer?
  self.instance_method(:initialize).owner == self
end

.identifierObject



163
164
165
# File 'lib/action_view/component/base.rb', line 163

def identifier
  source_location
end

.inherited(child) ⇒ Object



99
100
101
102
103
# File 'lib/action_view/component/base.rb', line 99

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

  super
end

.source_locationObject

Raises:

  • (NotImplementedError)


117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/action_view/component/base.rb', line 117

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 has_initializer?

  instance_method(:initialize).source_location[0]
end

.typeObject

we’ll eventually want to update this to support other types



159
160
161
# File 'lib/action_view/component/base.rb', line 159

def type
  "text/html"
end

.variantsObject



154
155
156
# File 'lib/action_view/component/base.rb', line 154

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

Instance Method Details

#controllerObject



68
69
70
# File 'lib/action_view/component/base.rb', line 68

def controller
  @controller ||= view_context.controller
end

#formatObject

:nodoc:



86
87
88
# File 'lib/action_view/component/base.rb', line 86

def format # :nodoc:
  @variant
end

#helpersObject

Provides a proxy to access helper methods through



73
74
75
# File 'lib/action_view/component/base.rb', line 73

def helpers
  @helpers ||= view_context
end

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



60
61
62
63
64
65
66
# File 'lib/action_view/component/base.rb', line 60

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>



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/action_view/component/base.rb', line 39

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



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

def view_cache_dependencies
  []
end

#virtual_pathObject

Removes the first part of the path and the extension.



78
79
80
# File 'lib/action_view/component/base.rb', line 78

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