class Volt::ModelController
Attributes
The section is assigned a reference to a “DomSection” which has the dom for the controllers view.
Public Class Methods
# File lib/volt/controllers/model_controller.rb, line 100 def self.model(val) self.default_model = val end
# File lib/volt/controllers/model_controller.rb, line 147 def self.new(volt_app, *args, &block) inst = allocate # In MRI initialize is private for some reason, so call it with send inst.send(:initialize, volt_app, *args, &block) if inst.instance_variable_get('@__init_called') inst.instance_variable_set('@__init_called', nil) else # Initialize was not called, we should warn since this is probably not # the intended behavior. Volt.logger.warn("super should be called when creating a custom initialize on class #{inst.class.to_s}") end inst end
# File lib/volt/controllers/model_controller.rb, line 166 def initialize(volt_app, *args) @volt_app = volt_app # Track that the initialize was called @__init_called = true default_model = self.class.default_model self.model = default_model if default_model if args[0] # Assign the first passed in argument to attrs self.attrs = args[0] # If a model attribute is passed in, we assign it directly self.model = attrs.locals[:model] if attrs.respond_to?(:model) end end
Public Instance Methods
Container returns the node that is parent to all nodes in the section.
# File lib/volt/controllers/model_controller.rb, line 29 def container check_section!('container') section.container_node end
# File lib/volt/controllers/model_controller.rb, line 200 def controller @controller ||= Model.new end
# File lib/volt/controllers/model_controller.rb, line 34 def dom_nodes check_section!('dom_nodes') section.range end
Walks the dom_nodes
range until it finds an element. Typically this will be the container element without the whitespace text nodes.
# File lib/volt/controllers/model_controller.rb, line 41 def first_element check_section!('first_element') range = dom_nodes nodes = `range.startContainer.childNodes` start_index = `range.startOffset` end_index = `range.endOffset` start_index.upto(end_index) do |index| node = `nodes[index]` # Return if an element if `node.nodeType === 1` return node end end return nil end
# File lib/volt/controllers/model_controller.rb, line 185 def go(url) Volt.logger.warn('Deprecation warning: `go` has been renamed to `redirect_to` for consistency with other frameworks.') redirect_to(url) end
loaded? is a quick way to see if the model for the controller is loaded yet. If the model is there, it asks the model if its loaded. If the model was set to a promise, it waits for the promise to resolve.
# File lib/volt/controllers/model_controller.rb, line 207 def loaded? if model.respond_to?(:loaded?) # There is a model and it is loaded return model.loaded? elsif last_promise || model.is_a?(Promise) # The model is a promise or is resolving return false else # Otherwise, its loaded return true end end
# File lib/volt/controllers/model_controller.rb, line 252 def method_missing(method_name, *args, &block) model = self.model if model model.send(method_name, *args, &block) else super end end
# File lib/volt/controllers/model_controller.rb, line 138 def model model = self.current_model # If the model is a proc, call it now model = model.call if model && model.is_a?(Proc) model end
Sets the current model on this controller
# File lib/volt/controllers/model_controller.rb, line 105 def model=(val) if val.is_a?(Promise) # Resolve the promise before setting self.last_promise = val val.then do |result| # Only assign if nothing else has been assigned since we started the resolve self.model = result if last_promise == val end.fail do |err| Volt.logger.error("Unable to resolve promise assigned to model on #{inspect}") end return end # Clear self.last_promise = nil # Start with a nil reactive value. self.current_model ||= Model.new if Symbol === val || String === val collections = [:page, :store, :params, :controller] if collections.include?(val.to_sym) self.current_model = send(val) else fail "#{val} is not the name of a valid model, choose from: #{collections.join(', ')}" end else self.current_model = val end end
Raw marks a string as html safe, so bindings can be rendered as html. With great power comes great responsibility.
# File lib/volt/controllers/model_controller.rb, line 231 def raw(str) # Promises need to have .to_s called using .then, since .to_s is a promise # method, so it won't be passed down to the value. if str.is_a?(Promise) str = str.then(&:to_s) else str = str.to_s unless str.is_a?(String) end str.html_safe end
Change the url
# File lib/volt/controllers/model_controller.rb, line 192 def redirect_to(url) # We might be in the rendering loop, so wait until the next tick before # we change the url Timers.next_tick do self.url.parse(url) end end
# File lib/volt/controllers/model_controller.rb, line 220 def require_login(message = 'You must login to access this area.') unless Volt.current_user_id flash._notices << message redirect_to '/login' stop_chain end end
Check if this controller responds_to method, or the model
# File lib/volt/controllers/model_controller.rb, line 244 def respond_to?(method_name) super || begin model = self.model model.respond_to?(method_name) if model end end
# File lib/volt/controllers/model_controller.rb, line 82 def trigger(event, *args) # Trigger on the current controller if an e- was setup on the component. component_event = attrs.send(:"e_#{event}") if component_event # Add a nil arg for the event, trim to arity args2 = (args + [nil])[0...component_event.arity] component_event.call(*args2) end args.unshift(self) # Trigger via jquery, so it bubbles up through the DOM `$(#{first_element}).trigger(#{event}, #{args});` # return nil, so we return a ruby object nil end
the u method provides an easy helper to render an unbonud binding. This means that the binding will not reactively update. If no bindings are bound on any model's from a query, the query will not be reactively listened to.
# File lib/volt/controllers/model_controller.rb, line 65 def u raise "the 'u' method requires a block" unless block_given? Volt::Computation.run_without_tracking { yield } end
yield_html
renders the content passed into a tag as a string. You can “`.watch!“` “`yield_html“` and it will be run again when anything in the template changes.
# File lib/volt/controllers/model_controller.rb, line 72 def yield_html if (template_path = attrs.content_template_path) @yield_renderer ||= StringTemplateRenderer.new(@volt_app, attrs.content_controller, template_path) @yield_renderer.html else # no template, empty string '' end end
Private Instance Methods
# File lib/volt/controllers/model_controller.rb, line 263 def check_section!(method_name) unless section raise "##{method_name} can't be called before the {action}_ready method is called" end end