Class: Volt::ModelController

Inherits:
Object
  • Object
show all
Includes:
Actions, CollectionHelpers, ReactiveAccessors
Defined in:
lib/volt/controllers/model_controller.rb

Direct Known Subclasses

NoticesController

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CollectionHelpers

#store, #url_for, #url_with

Methods included from Actions

included, #run_actions, #stop_chain

Methods included from ReactiveAccessors

#__reactive_dependency_get, included

Constructor Details

#initialize(volt_app, *args) ⇒ ModelController

Returns a new instance of ModelController.



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/volt/controllers/model_controller.rb', line 136

def initialize(volt_app, *args)
  @volt_app = volt_app
  @page = volt_app.page

  # 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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object



248
249
250
251
252
253
254
255
256
# File 'lib/volt/controllers/model_controller.rb', line 248

def method_missing(method_name, *args, &block)
  model = self.model

  if model
    model.send(method_name, *args, &block)
  else
    super
  end
end

Instance Attribute Details

#attrsObject

Returns the value of attribute attrs.



134
135
136
# File 'lib/volt/controllers/model_controller.rb', line 134

def attrs
  @attrs
end

#sectionObject

The section is assigned a reference to a “DomSection” which has the dom for the controllers view.



23
24
25
# File 'lib/volt/controllers/model_controller.rb', line 23

def section
  @section
end

Class Method Details

.model(val) ⇒ Object



70
71
72
# File 'lib/volt/controllers/model_controller.rb', line 70

def self.model(val)
  self.default_model = val
end

.new(volt_app, *args, &block) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/volt/controllers/model_controller.rb', line 117

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

Instance Method Details

#channelObject



195
196
197
# File 'lib/volt/controllers/model_controller.rb', line 195

def channel
  @page.channel
end

#containerObject

Container returns the node that is parent to all nodes in the section.



29
30
31
# File 'lib/volt/controllers/model_controller.rb', line 29

def container
  section.container_node
end

#controllerObject



203
204
205
# File 'lib/volt/controllers/model_controller.rb', line 203

def controller
  @controller ||= Model.new
end

#cookiesObject



187
188
189
# File 'lib/volt/controllers/model_controller.rb', line 187

def cookies
  @page.cookies
end

#dom_nodesObject



33
34
35
# File 'lib/volt/controllers/model_controller.rb', line 33

def dom_nodes
  section.range
end

#first_elementObject

Walks the dom_nodes range until it finds an element. Typically this will be the container element without the whitespace text nodes.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/volt/controllers/model_controller.rb', line 39

def 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

#flashObject



175
176
177
# File 'lib/volt/controllers/model_controller.rb', line 175

def flash
  @page.flash
end

#go(url) ⇒ Object



156
157
158
159
160
# File 'lib/volt/controllers/model_controller.rb', line 156

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?Boolean

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.

Returns:



210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/volt/controllers/model_controller.rb', line 210

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

#local_storeObject



183
184
185
# File 'lib/volt/controllers/model_controller.rb', line 183

def local_store
  @page.local_store
end

#modelObject



108
109
110
111
112
113
114
115
# File 'lib/volt/controllers/model_controller.rb', line 108

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

#model=(val) ⇒ Object

Sets the current model on this controller



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/volt/controllers/model_controller.rb', line 75

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

#pageObject



171
172
173
# File 'lib/volt/controllers/model_controller.rb', line 171

def page
  @page.page
end

#paramsObject



179
180
181
# File 'lib/volt/controllers/model_controller.rb', line 179

def params
  @page.params
end

#raw(str) ⇒ Object

Raw marks a string as html safe, so bindings can be rendered as html. With great power comes great responsibility.



234
235
236
237
# File 'lib/volt/controllers/model_controller.rb', line 234

def raw(str)
  str = str.to_s unless str.is_a?(String)
  str.html_safe
end

#redirect_to(url) ⇒ Object

Change the url



163
164
165
166
167
168
169
# File 'lib/volt/controllers/model_controller.rb', line 163

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

#require_login(message = 'You must login to access this area.') ⇒ Object



223
224
225
226
227
228
229
230
# File 'lib/volt/controllers/model_controller.rb', line 223

def (message = 'You must login to access this area.')
  unless Volt.current_user_id
    flash._notices << message
    redirect_to '/login'

    stop_chain
  end
end

#respond_to?(method_name) ⇒ Boolean

Check if this controller responds_to method, or the model

Returns:



240
241
242
243
244
245
246
# File 'lib/volt/controllers/model_controller.rb', line 240

def respond_to?(method_name)
  super || begin
    model = self.model

    model.respond_to?(method_name) if model
  end
end

#tasksObject



199
200
201
# File 'lib/volt/controllers/model_controller.rb', line 199

def tasks
  @page.tasks
end

#urlObject



191
192
193
# File 'lib/volt/controllers/model_controller.rb', line 191

def url
  @page.url
end

#yield_htmlObject

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.



60
61
62
63
64
65
66
67
68
# File 'lib/volt/controllers/model_controller.rb', line 60

def yield_html
  if (template_path = attrs.content_template_path)
    @yield_renderer ||= StringTemplateRenderer.new(@volt_app, self, template_path)
    @yield_renderer.html
  else
    # no template, empty string
    ''
  end
end