Class: Page

Inherits:
Record show all
Includes:
Authentication, HTMLDecorator
Defined in:
lib/yodel/models/pages/page.rb

Constant Summary

Constants included from Authentication

Authentication::AUTHORIZATION_KEYS

Constants inherited from AbstractRecord

AbstractRecord::CALLBACKS, AbstractRecord::FIELD_CALLBACKS, AbstractRecord::ORDERS

Instance Attribute Summary

Attributes inherited from Record

#mixins, #model, #model_record, #real_record

Attributes inherited from SiteRecord

#site

Attributes inherited from AbstractRecord

#changed, #errors, #stash, #typecast, #values

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HTMLDecorator

#delete_button, #delete_link, #form_for_page, #immediately, #on_click, #paragraph, #paragraphs_from

Methods included from Authentication

#current_user, #logged_in?, #login, #logout, #prompt_login, #store_authenticated_user

Methods inherited from Record

#all_children, #append_to_siblings, #children_and_self, #collection, #create_eigenmodel, #create_mixin_instances, #default_values, #delegate_mixins, #destroy_children, #field_sections, #fields, #first_non_blank_response_to, #first_parent, #first_response_to, #get_binding, #has_eigenmodel?, #initialize, #insert_in_siblings, #inspect_hash, #load_model, #model_name, #parent?, #parents, #perform_reload, #prepare_reload_params, #remove_eigenmodel, #remove_from_siblings, #root?, #run_record_after_create_callbacks, #run_record_after_destroy_callbacks, #run_record_after_save_callbacks, #run_record_after_update_callbacks, #run_record_after_validation_callbacks, #run_record_before_create_callbacks, #run_record_before_destroy_callbacks, #run_record_before_save_callbacks, #run_record_before_update_callbacks, #run_record_before_validation_callbacks, #siblings, #to_str, #update_search_keywords, #user_allowed_to_create?, #user_allowed_to_delete?, #user_allowed_to_update?, #user_allowed_to_view?

Methods inherited from SiteRecord

#default_values, #initialize, #inspect_hash, #perform_reload, #prepare_reload_params, #site_id

Methods included from SiteModel

#load, #scoped, #scoped_for

Methods included from MongoModel

#collection, #load, #scoped

Methods included from AbstractModel

#embed_many, #embed_one, #field, #fields, #many, #modify_field, #one, #remove_field

Methods inherited from MongoRecord

#collection, #default_values, #fields, #id, #increment!, #inspect_hash, #load_from_mongo, #load_mongo_document, #perform_destroy, #perform_reload, #perform_save, #set_id

Methods inherited from AbstractRecord

#changed!, #changed?, #clear_key, #default_values, #destroy, #destroyed?, #eql?, #errors?, #field, #field?, #field_was, #fields, #from_json, #get, #get_meta, #get_raw, #hash, #id, #increment!, inherited, #initialize, #inspect, #inspect_hash, #inspect_value, #method_missing, #new?, #prepare_reload_params, #present?, #reload, #save, #save_without_validation, #search_terms, #set, #set_meta, #set_raw, #to_json, #to_str, #trigger_field_callback, #update, #valid?

Constructor Details

This class inherits a constructor from Record

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class AbstractRecord

Class Method Details

.respond_to(http_method) ⇒ Object


Response content




101
102
103
104
105
106
# File 'lib/yodel/models/pages/page.rb', line 101

def self.respond_to(http_method)
  # FIXME: this is not thread safe
  @_http_method = http_method
  yield
  @_http_method = nil
end

.with(mime_type, &block) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/yodel/models/pages/page.rb', line 108

def self.with(mime_type, &block)
  # two instance methods may be defined from the response definition
  action_name             = "respond_to_#{@_http_method}_with_#{mime_type}"
  default_action_name     = "default_response_to_#{@_http_method}"
  default_action_mime_var = "@default_response_to_#{@_http_method}_mime_type"
  
  # create or overwrite the main action for this http_method/mime_type pair
  define_method(action_name, block)
  
  # if this is the first response definition for the http_method, assign it
  # as the default response for requests matching the http_method, but not
  # matching a mime_type that has been responded to
  unless instance_methods(false).include?(default_action_name.to_sym)
    define_method(default_action_name, block)
    instance_variable_set(default_action_mime_var, Yodel.mime_types[mime_type])
  end
end

Instance Method Details

#assign_child_pathsObject



60
61
62
63
64
# File 'lib/yodel/models/pages/page.rb', line 60

def assign_child_paths
  return unless path_changed? || (!path.nil? && values['path'].nil?)
  return unless @errors.empty? # @errors.present? == invalid
  children.each {|child| child.assign_path(path)}
end

#assign_path(prefix = nil) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/yodel/models/pages/page.rb', line 35

def assign_path(prefix=nil)
  if prefix
    prefix = '' if prefix == '/' # when the root page is parent, prefix will be "/"
    base = prefix + '/' + permalink
  else
    base = '/' + parents.reverse[1..-1].collect(&:permalink).join('/')
  end
  
  permalink_character = site.option('pages.permalink_character') || '-'
  self.path = base
  count = 0
  
  while site.pages.where(:path => self.path, :_id.ne => self.id).exists?
    count += 1
    self.path = "#{base}#{permalink_character}#{count}"
  end
  
  # child pages are called with prefix supplied
  # FIXME: with the identity map, this call could save another record which has been modified
  # elsewhere; change to update path only, not a full save
  save_without_validation unless prefix.nil?
  children.each {|child| child.assign_path(self.path)}
end


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/yodel/models/pages/page.rb', line 12

def assign_permalink
  return unless (title_changed? && title?) || (!title.nil? && values['title'].nil?)
  
  # until we detect changes to fields used by cached functions, force a refresh of the value
  generate_unloaded_field('title') if field('title').type == 'Function'
  
  permalink_character = site.option('pages.permalink_character') || '-'
  base_permalink = title.parameterize(permalink_character)
  suffix = ''
  count  = 0
  
  # ensure other pages don't have the same path as this page
  page_siblings = siblings.all.select {|record| record.field?('permalink')}
  while page_siblings.any? {|page| page.permalink == base_permalink + suffix}
    count += 1
    suffix = "#{permalink_character}#{count}"
  end
  
  # set the page's permalink, then construct its path and reset any child paths
  self.permalink = base_permalink + suffix
  assign_path
end

#content(*section) ⇒ Object



230
231
232
233
234
235
236
# File 'lib/yodel/models/pages/page.rb', line 230

def content(*section)
  if section.empty?
    @content ||= get('content')
  else
    instance_variable_get("@content_for_#{section.first}") || ''
  end
end

#content_for(section, options = {}, &block) ⇒ Object



238
239
240
241
242
243
244
245
# File 'lib/yodel/models/pages/page.rb', line 238

def content_for(section, options={}, &block)
  if block_given?
    content = Ember::Template.content_from_block(block).join
  elsif options.key?(:partial)
    content = partial(options[:partial])
  end
  instance_variable_set("@content_for_#{section}", content)
end

#envObject



171
# File 'lib/yodel/models/pages/page.rb', line 171

def env;            @_request.env; end

#flashObject



78
79
80
# File 'lib/yodel/models/pages/page.rb', line 78

def flash
  @flash ||= Flash.new(session)
end

#form_for(record, action, options = {}, &block) ⇒ Object


Forms




86
87
88
89
90
91
92
93
94
95
# File 'lib/yodel/models/pages/page.rb', line 86

def form_for(record, action, options={}, &block)
  options[:method] = record.new? ? 'post' : 'put'
  if options[:remote]
    components = action.split('?')
    components[0] += '.json' unless components.first.end_with?('.json')
    action = components.join('?')
    options[:success] = 'window.location = record.path;' if record.new?
  end
  FormBuilder.new(record, action, options, &block).render
end

#layout(mime_type, editing = false) ⇒ Object

FIXME: make layout take a string or symbol param, remove .to_s from render_or_default, change blog.rb layout to use a symbol not string, check all other calls to layout() and change appropriately Determine the first best layout to be used by this page for rendering

Raises:



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/yodel/models/pages/page.rb', line 187

def layout(mime_type, editing=false)
  # if we're in production we'll have a reference to a layout record
  #return page_layout_record if page_layout_record # FIXME: implement layout caching
  
  # try and return a layout by name or by the name of the page's class
  layout_name = editing ? edit_layout : page_layout
  layout = site.layouts.where(name: layout_name, mime_type: mime_type).first
  
  unless layout
    layout_name = model.name.underscore
    layout_name = "edit_#{layout_name}" if editing
    layout = site.layouts.where(name: layout_name, mime_type: mime_type).first
  end
  
  return layout if layout
  
  # otherwise fall back to the parent's layout
  return parent.layout(mime_type) unless parent.nil?
  raise LayoutNotFound
end


74
75
76
# File 'lib/yodel/models/pages/page.rb', line 74

def menu(name)
  site.menus[name.to_s].render(self)
end

#mime_typeObject



175
# File 'lib/yodel/models/pages/page.rb', line 175

def mime_type;      @_mime_type; end

#mime_type=(m) ⇒ Object



176
# File 'lib/yodel/models/pages/page.rb', line 176

def mime_type=(m);  @_mime_type = m; end

#page(*args) ⇒ Object



255
256
257
258
259
260
261
# File 'lib/yodel/models/pages/page.rb', line 255

def page(*args)
  if args.empty?
    self
  else
    site.pages.where(path: args.first).first
  end
end

#paramsObject



172
# File 'lib/yodel/models/pages/page.rb', line 172

def params;         @_request.params; end

#partial(name) ⇒ Object

Raises:



247
248
249
250
251
252
253
# File 'lib/yodel/models/pages/page.rb', line 247

def partial(name)
  name = name.to_s
  name = name + '.html' unless name.end_with?('.html')
  path = File.join(site.partials_directory, name)
  raise LayoutNotFound, path unless File.exist?(path)
  Ember::Template.new(IO.read(path), {source_file: path}).render(get_binding)
end

#render_layout(name, mime_type) ⇒ Object

Raises:



208
209
210
211
212
# File 'lib/yodel/models/pages/page.rb', line 208

def render_layout(name, mime_type)
  layout_record = site.layouts.where(name: name, mime_type: mime_type.to_s).first
  raise LayoutNotFound if layout_record.nil?
  layout_record.render(self)
end

#render_or_default(mime_type, &block) ⇒ Object


Default request handling




218
219
220
221
222
223
224
# File 'lib/yodel/models/pages/page.rb', line 218

def render_or_default(mime_type, &block)
  @content ||= content
  editing = @_request && params && params['action'] == 'edit'
  layout(mime_type.to_s, editing).render(self)
rescue LayoutNotFound
  yield
end

#requestObject

basic environment accessors



169
# File 'lib/yodel/models/pages/page.rb', line 169

def request;        @_request; end

#request=(r) ⇒ Object



170
# File 'lib/yodel/models/pages/page.rb', line 170

def request=(r);    @_request = r; end

#respond_to_request(request, response, mime_type) ⇒ Object

request handling



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/yodel/models/pages/page.rb', line 127

def respond_to_request(request, response, mime_type)
  # initialise request & response for use by the environment accessors
  @_request   = request
  @_response  = response
  @_mime_type = mime_type
  
  # determine the default action name for the request
  http_method = request.request_method.downcase
  action = "respond_to_#{http_method}_with_#{mime_type.name}"
  
  # if there is no action for the request, default to the first for the http_method of the request
  if !respond_to?(action)
    action = "default_response_to_#{http_method}"
    
    if !respond_to?(action)
      response.write "Unable to respond to a request using http method: #{http_method}"
      response['Content-Type'] = 'text/plain'
      return
    else
      default_mime = self.class.instance_variable_get("@default_response_to_#{http_method}_mime_type")
      mime_type = default_mime if mime_type != default_mime
      Yodel.config.logger.warn "No response matches this request, falling back to a default response."
    end
  end
  
  # only send a builder object as a parameter to the action if required
  if mime_type.has_builder?
    data = send(action, mime_type.create_builder)
  else
    data = send(action)
  end
  return if @finished
  
  # process the response and set headers
  response.write mime_type.process(data)
  response['Content-Type'] = "#{mime_type.default_mime_type}; charset=utf-8"
  
  # write the flash to the session if appropriate
  @flash.finalize if @flash
end

#responseObject



173
# File 'lib/yodel/models/pages/page.rb', line 173

def response;       @_response; end

#response=(r) ⇒ Object



174
# File 'lib/yodel/models/pages/page.rb', line 174

def response=(r);   @_response = r; end

#sessionObject



177
# File 'lib/yodel/models/pages/page.rb', line 177

def session;        @_request.env['rack.session'] ||= {}; end

#set_content(content) ⇒ Object



226
227
228
# File 'lib/yodel/models/pages/page.rb', line 226

def set_content(content)
  @content = content
end

#snippet(name) ⇒ Object


Layout helpers




70
71
72
# File 'lib/yodel/models/pages/page.rb', line 70

def snippet(name)
  site.snippets[name.to_s].content
end

#status(code) ⇒ Object

By default, responses are assumed to be 200 (successful). Use status to change the code returned along with your response content.



181
182
183
# File 'lib/yodel/models/pages/page.rb', line 181

def status(code)
  response.status = code
end

#user_allowed_to?(action) ⇒ Boolean

Returns:

  • (Boolean)


263
264
265
266
267
268
269
270
# File 'lib/yodel/models/pages/page.rb', line 263

def user_allowed_to?(action)
  allowed = super(current_user(:page), action)
  return true if allowed
  
  
  flash[:permission_denied] = action
  false
end