Class: ViewComponent::Base
- Inherits:
-
ActionView::Base
- Object
- ActionView::Base
- ViewComponent::Base
- Includes:
- ActiveSupport::Configurable, Previewable
- Defined in:
- lib/view_component/base.rb
Class Method Summary collapse
- .call_method_name(variant) ⇒ 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
- .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
- #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.
74 |
# File 'lib/view_component/base.rb', line 74 def initialize(*); end |
Class Method Details
.call_method_name(variant) ⇒ Object
142 143 144 145 146 147 148 |
# File 'lib/view_component/base.rb', line 142 def call_method_name(variant) if variant.present? && variants.include?(variant) "call_#{variant}" else "call" end 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.
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/view_component/base.rb', line 175 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 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], -1 |
.compile! ⇒ Object
168 169 170 |
# File 'lib/view_component/base.rb', line 168 def compile! compile(raise_template_errors: true) end |
.compiled? ⇒ Boolean
160 161 162 |
# File 'lib/view_component/base.rb', line 160 def compiled? @compiled && ActionView::Base.cache_template_loading end |
.identifier ⇒ Object
204 205 206 |
# File 'lib/view_component/base.rb', line 204 def identifier source_location end |
.inherited(child) ⇒ Object
134 135 136 137 138 139 140 |
# File 'lib/view_component/base.rb', line 134 def inherited(child) if defined?(Rails) child.include Rails.application.routes.url_helpers unless child < Rails.application.routes.url_helpers end super end |
.inlined? ⇒ Boolean
164 165 166 |
# File 'lib/view_component/base.rb', line 164 def inlined? instance_methods(false).grep(/^call/).present? && templates.empty? end |
.source_location ⇒ Object
150 151 152 153 154 155 156 157 158 |
# File 'lib/view_component/base.rb', line 150 def source_location @source_location ||= begin # Require `#initialize` to be defined so that we can use `method#source_location` # to look up the filename of the component. 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
200 201 202 |
# File 'lib/view_component/base.rb', line 200 def type "text/html" end |
.variants ⇒ Object
195 196 197 |
# File 'lib/view_component/base.rb', line 195 def variants templates.map { |template| template[:variant] } end |
.with_content_areas(*areas) ⇒ Object
208 209 210 211 212 213 214 |
# File 'lib/view_component/base.rb', line 208 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
66 67 68 |
# File 'lib/view_component/base.rb', line 66 def before_render_check # noop end |
#controller ⇒ Object
84 85 86 |
# File 'lib/view_component/base.rb', line 84 def controller @controller ||= view_context.controller end |
#format ⇒ Object
:nodoc:
102 103 104 |
# File 'lib/view_component/base.rb', line 102 def format # :nodoc: @variant end |
#helpers ⇒ Object
Provides a proxy to access helper methods through
89 90 91 |
# File 'lib/view_component/base.rb', line 89 def helpers @helpers ||= view_context end |
#render(options = {}, args = {}, &block) ⇒ Object
76 77 78 79 80 81 82 |
# File 'lib/view_component/base.rb', line 76 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
70 71 72 |
# File 'lib/view_component/base.rb', line 70 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>
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/view_component/base.rb', line 41 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
98 99 100 |
# File 'lib/view_component/base.rb', line 98 def view_cache_dependencies [] end |
#virtual_path ⇒ Object
Removes the first part of the path and the extension.
94 95 96 |
# File 'lib/view_component/base.rb', line 94 def virtual_path self.class.source_location.gsub(%r{(.*app/components)|(\.rb)}, "") end |
#with(area, content = nil, &block) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/view_component/base.rb', line 106 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 |