Class: ViewComponent::Base
- Inherits:
-
ActionView::Base
- Object
- ActionView::Base
- ViewComponent::Base
- Includes:
- ActiveSupport::Configurable, Previewable
- Defined in:
- lib/view_component/base.rb
Class Attribute Summary collapse
-
.source_location ⇒ Object
Returns the value of attribute source_location.
Class Method Summary collapse
- .call_method_name(variant) ⇒ Object
- .collection_parameter_name ⇒ Object
-
.compile(raise_template_errors: false) ⇒ Object
Compile templates to instance methods, assuming they haven’t been compiled already.
- .compile! ⇒ Object
- .compiled? ⇒ Boolean
- .identifier ⇒ Object
- .inherited(child) ⇒ Object
- .inlined? ⇒ Boolean
- .short_identifier ⇒ Object
-
.type ⇒ Object
we’ll eventually want to update this to support other types.
- .variants ⇒ Object
-
.with_collection(*args) ⇒ Object
Render a component collection.
-
.with_collection_parameter(param) ⇒ Object
Support overriding this component’s collection parameter name.
- .with_content_areas(*areas) ⇒ Object
Instance Method Summary collapse
- #before_render_check ⇒ Object
- #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, &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.
84 |
# File 'lib/view_component/base.rb', line 84 def initialize(*); end |
Class Attribute Details
.source_location ⇒ Object
Returns the value of attribute source_location.
144 145 146 |
# File 'lib/view_component/base.rb', line 144 def source_location @source_location end |
Class Method Details
.call_method_name(variant) ⇒ Object
156 157 158 159 160 161 162 |
# File 'lib/view_component/base.rb', line 156 def call_method_name(variant) if variant.present? && variants.include?(variant) "call_#{variant}" else "call" end end |
.collection_parameter_name ⇒ Object
237 238 239 |
# File 'lib/view_component/base.rb', line 237 def collection_parameter_name (@with_collection_parameter || name.demodulize.underscore.chomp("_component")).to_sym end |
.compile(raise_template_errors: 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.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/view_component/base.rb', line 179 def compile(raise_template_errors: false) return if compiled? || inlined? if template_errors.present? raise ViewComponent::TemplateError.new(template_errors) if raise_template_errors return false end # If template name annotations are turned on, a line is dynamically # added with a comment. In this case, we want to return a different # starting line number so errors that are raised will point to the # correct line in the component template. line_number = if ActionView::Base.respond_to?(:annotate_template_file_names) && ActionView::Base.annotate_template_file_names -2 else -1 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", template[:path], line_number |
.compile! ⇒ Object
172 173 174 |
# File 'lib/view_component/base.rb', line 172 def compile! compile(raise_template_errors: true) end |
.compiled? ⇒ Boolean
164 165 166 |
# File 'lib/view_component/base.rb', line 164 def compiled? @compiled && ActionView::Base.cache_template_loading end |
.identifier ⇒ Object
220 221 222 |
# File 'lib/view_component/base.rb', line 220 def identifier source_location end |
.inherited(child) ⇒ Object
146 147 148 149 150 151 152 153 154 |
# File 'lib/view_component/base.rb', line 146 def inherited(child) if defined?(Rails) child.include Rails.application.routes.url_helpers unless child < Rails.application.routes.url_helpers end child.source_location = caller_locations(1, 1)[0].absolute_path super end |
.inlined? ⇒ Boolean
168 169 170 |
# File 'lib/view_component/base.rb', line 168 def inlined? instance_methods(false).grep(/^call/).present? && templates.empty? end |
.short_identifier ⇒ Object
80 81 82 |
# File 'lib/view_component/base.rb', line 80 def self.short_identifier @short_identifier ||= defined?(Rails.root) ? source_location.sub("#{Rails.root}/", "") : source_location end |
.type ⇒ Object
we’ll eventually want to update this to support other types
216 217 218 |
# File 'lib/view_component/base.rb', line 216 def type "text/html" end |
.variants ⇒ Object
211 212 213 |
# File 'lib/view_component/base.rb', line 211 def variants templates.map { |template| template[:variant] } end |
.with_collection(*args) ⇒ Object
Render a component collection.
19 20 21 |
# File 'lib/view_component/base.rb', line 19 def self.with_collection(*args) Collection.new(self, *args) end |
.with_collection_parameter(param) ⇒ Object
Support overriding this component’s collection parameter name
233 234 235 |
# File 'lib/view_component/base.rb', line 233 def with_collection_parameter(param) @with_collection_parameter = param end |
.with_content_areas(*areas) ⇒ Object
224 225 226 227 228 229 230 |
# File 'lib/view_component/base.rb', line 224 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
#before_render_check ⇒ Object
72 73 74 |
# File 'lib/view_component/base.rb', line 72 def before_render_check # noop end |
#controller ⇒ Object
94 95 96 |
# File 'lib/view_component/base.rb', line 94 def controller @controller ||= view_context.controller end |
#format ⇒ Object
:nodoc:
112 113 114 |
# File 'lib/view_component/base.rb', line 112 def format # :nodoc: @variant end |
#helpers ⇒ Object
Provides a proxy to access helper methods through
99 100 101 |
# File 'lib/view_component/base.rb', line 99 def helpers @helpers ||= view_context end |
#render(options = {}, args = {}, &block) ⇒ Object
86 87 88 89 90 91 92 |
# File 'lib/view_component/base.rb', line 86 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
76 77 78 |
# File 'lib/view_component/base.rb', line 76 def render? true end |
#render_in(view_context, &block) ⇒ Object
Entrypoint for rendering components.
view_context: ActionView context from calling view 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 < ViewComponent::Base
def initialize(title:)
@title = title
end
end
app/components/my_component.html.erb <span title=“<%= @title %>”>Hello, <%= content %>!</span>
In use: <%= render MyComponent.new(title: “greeting”) do %>world<% end %> returns: <span title=“greeting”>Hello, world!</span>
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/view_component/base.rb', line 47 def render_in(view_context, &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(self, &block) if block_given? before_render_check if render? send(self.class.call_method_name(@variant)) else "" end ensure @current_template = old_current_template end |
#view_cache_dependencies ⇒ Object
108 109 110 |
# File 'lib/view_component/base.rb', line 108 def view_cache_dependencies [] end |
#virtual_path ⇒ Object
Removes the first part of the path and the extension.
104 105 106 |
# File 'lib/view_component/base.rb', line 104 def virtual_path self.class.source_location.gsub(%r{(.*app/components)|(\.rb)}, "") end |
#with(area, content = nil, &block) ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/view_component/base.rb', line 116 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 |