Class: ActionView::Component::Base
- Inherits:
-
Base
- Object
- Base
- ActionView::Component::Base
- Includes:
- Previewable, ActiveModel::Validations, ActiveSupport::Configurable
- Defined in:
- lib/action_view/component/base.rb
Class Method Summary collapse
- .call_method_name(variant) ⇒ Object
-
.compile(validate: false) ⇒ Object
Compile templates to instance methods, assuming they haven’t been compiled already.
- .compile! ⇒ Object
- .compiled? ⇒ Boolean
- .identifier ⇒ Object
- .inherited(child) ⇒ Object
- .source_location ⇒ Object
-
.type ⇒ Object
we’ll eventually want to update this to support other types.
- .variants ⇒ Object
- .with_content_areas(*areas) ⇒ Object
Instance Method Summary collapse
- #controller ⇒ Object
-
#format ⇒ Object
:nodoc:.
-
#helpers ⇒ Object
Provides a proxy to access helper methods through.
-
#initialize ⇒ Base
constructor
A new instance of Base.
- #render(options = {}, args = {}, &block) ⇒ Object
- #render? ⇒ Boolean
-
#render_in(view_context, *args, &block) ⇒ Object
Entrypoint for rendering components.
- #view_cache_dependencies ⇒ Object
-
#virtual_path ⇒ Object
Removes the first part of the path and the extension.
- #with(area, content = nil, &block) ⇒ Object
Constructor Details
#initialize ⇒ Base
Returns a new instance of Base.
69 |
# File 'lib/action_view/component/base.rb', line 69 def initialize(*); end |
Class Method Details
.call_method_name(variant) ⇒ Object
135 136 137 138 139 140 141 |
# File 'lib/action_view/component/base.rb', line 135 def call_method_name(variant) if variant.present? && variants.include?(variant) "call_#{variant}" else "call" end end |
.compile(validate: false) ⇒ Object
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.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/action_view/component/base.rb', line 170 def compile(validate: false) return if compiled? if template_errors.present? raise ActionView::Component::TemplateError.new(template_errors) if validate return false end 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 |
.compile! ⇒ Object
163 164 165 |
# File 'lib/action_view/component/base.rb', line 163 def compile! compile(validate: true) end |
.compiled? ⇒ Boolean
159 160 161 |
# File 'lib/action_view/component/base.rb', line 159 def compiled? @compiled && ActionView::Base.cache_template_loading end |
.identifier ⇒ Object
199 200 201 |
# File 'lib/action_view/component/base.rb', line 199 def identifier source_location end |
.inherited(child) ⇒ Object
129 130 131 132 133 |
# File 'lib/action_view/component/base.rb', line 129 def inherited(child) child.include Rails.application.routes.url_helpers unless child < Rails.application.routes.url_helpers super end |
.source_location ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/action_view/component/base.rb', line 143 def source_location @source_location ||= begin # 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. # initialize_method = instance_method(:initialize) initialize_method.source_location[0] if initialize_method.owner == self end end |
.type ⇒ Object
we’ll eventually want to update this to support other types
195 196 197 |
# File 'lib/action_view/component/base.rb', line 195 def type "text/html" end |
.variants ⇒ Object
190 191 192 |
# File 'lib/action_view/component/base.rb', line 190 def variants templates.map { |template| template[:variant] } end |
.with_content_areas(*areas) ⇒ Object
203 204 205 206 207 208 209 |
# File 'lib/action_view/component/base.rb', line 203 def with_content_areas(*areas) if areas.include?(:content) raise ArgumentError.new ":content is a reserved content area name. Please use another name, such as ':body'" end attr_reader *areas self.content_areas = areas end |
Instance Method Details
#controller ⇒ Object
79 80 81 |
# File 'lib/action_view/component/base.rb', line 79 def controller @controller ||= view_context.controller end |
#format ⇒ Object
:nodoc:
97 98 99 |
# File 'lib/action_view/component/base.rb', line 97 def format # :nodoc: @variant end |
#helpers ⇒ Object
Provides a proxy to access helper methods through
84 85 86 |
# File 'lib/action_view/component/base.rb', line 84 def helpers @helpers ||= view_context end |
#render(options = {}, args = {}, &block) ⇒ Object
71 72 73 74 75 76 77 |
# File 'lib/action_view/component/base.rb', line 71 def render( = {}, args = {}, &block) if .is_a?(String) || (.is_a?(Hash) && .has_key?(:partial)) view_context.render(, args, &block) else super end end |
#render? ⇒ Boolean
65 66 67 |
# File 'lib/action_view/component/base.rb', line 65 def render? true 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>
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/action_view/component/base.rb', line 42 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 return "" unless render? old_current_template = @current_template @current_template = self @content = view_context.capture(self, &block) if block_given? validate! send(self.class.call_method_name(@variant)) ensure @current_template = old_current_template end |
#view_cache_dependencies ⇒ Object
93 94 95 |
# File 'lib/action_view/component/base.rb', line 93 def view_cache_dependencies [] end |
#virtual_path ⇒ Object
Removes the first part of the path and the extension.
89 90 91 |
# File 'lib/action_view/component/base.rb', line 89 def virtual_path self.class.source_location.gsub(%r{(.*app/components)|(\.rb)}, "") end |
#with(area, content = nil, &block) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/action_view/component/base.rb', line 101 def with(area, content = nil, &block) unless content_areas.include?(area) raise ArgumentError.new "Unknown content_area '#{area}' - expected one of '#{content_areas}'" end if block_given? content = view_context.capture(&block) end instance_variable_set("@#{area}".to_sym, content) nil end |