Class: ActionView::Component::Base

Inherits:
Base
  • Object
show all
Includes:
Previews, 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.



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

def initialize(*); end

Class Method Details

.call_method_name(variant) ⇒ Object



116
117
118
119
120
121
122
# File 'lib/action_view/component/base.rb', line 116

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.



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

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

.identifierObject



166
167
168
# File 'lib/action_view/component/base.rb', line 166

def identifier
  ""
end

.inherited(child) ⇒ Object



110
111
112
113
114
# File 'lib/action_view/component/base.rb', line 110

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

  super
end

.source_locationObject

Raises:

  • (NotImplementedError)


124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/action_view/component/base.rb', line 124

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

.typeObject

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



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

def type
  "text/html"
end

.variantsObject



157
158
159
# File 'lib/action_view/component/base.rb', line 157

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

Instance Method Details

#controllerObject



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

def controller
  @controller ||= view_context.controller
end

#formatObject

:nodoc:



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

def format # :nodoc:
  @variant
end

#helpersObject

Provides a proxy to access helper methods through



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

def helpers
  @helpers ||= view_context
end

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



65
66
67
68
69
70
71
# File 'lib/action_view/component/base.rb', line 65

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>



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/action_view/component/base.rb', line 44

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



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

def view_cache_dependencies
  []
end

#virtual_pathObject

Removes the first part of the path and the extension.



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

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