Class: Cms::Page

Inherits:
ActiveRecord::Base
  • Object
show all
Extended by:
DefaultAccessible
Includes:
Concerns::Addressable::DeprecatedPageAccessors
Defined in:
app/models/cms/page.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DefaultAccessible

non_permitted_params, permitted_params

Methods included from Concerns::Addressable::DeprecatedPageAccessors

#build_node, #section, #section=, #section_id, #section_id=

Class Method Details

.connected_to(b) ⇒ Object

This scope will accept a connectable object or a Hash. The Hash is expect to have a value for the key :connectable, which is the connectable object, and possibly a value for the key :version. The Hash contains a versioned connectable object, it will use the value in :version if present, otherwise it will use the version of the object. In either case of a connectable object or a Hash, if the object is not versioned, no version will be used



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

def connected_to(b)
  if b.is_a?(Hash)
    obj = b[:connectable]
    if obj.class.versioned?
      ver = b[:version] ? b[:version] : obj.version
    else
      ver = nil
    end
  else
    obj = b
    ver = obj.class.versioned? ? obj.version : nil
  end

  if ver
    query = where(["#{Cms::Connector.table_name}.connectable_id = ? and #{Cms::Connector.table_name}.connectable_type = ? and #{Cms::Connector.table_name}.connectable_version = ?", obj.id, obj.class.base_class.name, ver])
  else
    query = where(["#{Cms::Connector.table_name}.connectable_id = ? and #{Cms::Connector.table_name}.connectable_type = ?", obj.id, obj.class.base_class.name])
  end
  query.includes(:connectors).references(:connectors)

end

.find_draft(id_or_path) ⇒ Cms::Page::Version

Find the latest draft of a given page.

Parameters:

  • id_or_path (Integer | String)

    The id or path of the page

Returns:

  • (Cms::Page::Version)

    The version of the page as of the current Draft.



96
97
98
99
100
101
102
103
104
105
106
107
# File 'app/models/cms/page.rb', line 96

def self.find_draft(id_or_path)
  if id_or_path.is_a? String
    current = self.with_path(id_or_path).first
  else
    current = self.find(id_or_path)
  end
  if current
    current.as_of_draft_version
  else
    raise Cms::Errors::DraftNotFound
  end
end

.find_live(path) ⇒ Cms::Page

Finds the live version of a Page.

Parameters:

  • path (String)

    The relative path to the page

Returns:



113
114
115
116
117
118
119
# File 'app/models/cms/page.rb', line 113

def self.find_live(path)
  result = find_live_by_path(path)
  unless result
    raise Cms::Errors::ContentNotFound
  end
  result
end

.find_live_by_path(path) ⇒ Cms::Page

Find live version of a page.

Returns:



123
124
125
# File 'app/models/cms/page.rb', line 123

def self.find_live_by_path(path)
  published.not_archived.where(path: path).first
end

.named(name) ⇒ Object



22
23
24
# File 'app/models/cms/page.rb', line 22

def named(name)
  where(["#{table_name}.name = ?", name])
end

.permitted_paramsObject



59
60
61
# File 'app/models/cms/page.rb', line 59

def permitted_params
  super + [:visibility, :publish_on_save]
end

.with_path(path) ⇒ Object



26
27
28
# File 'app/models/cms/page.rb', line 26

def with_path(path)
  where(["#{table_name}.path = ?", path])
end

Instance Method Details

#actual_pathObject



3
4
5
# File 'app/models/cms/page.rb', line 3

def actual_path
  path
end

#add_content(connectable, container = :main) ⇒ Object Also known as: create_connector

Adds a Content block to this page.

Parameters:

  • connectable (ContentBlock)

    The content block to be added

  • container (Symbol) (defaults to: :main)

    The container to add it in (default :main)



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'app/models/cms/page.rb', line 211

def add_content(connectable, container=:main)
  transaction do
    raise "Connectable is nil" unless connectable
    raise "Container is required" if container.blank?
    #should_publish =  published? &&
    #              connectable.connected_page &&
    #              (connectable.class.publishable? ? connectable.published? : true)
    should_publish = false
    update_attributes(
        :version_comment => "#{connectable} was added to the '#{container}' container",
        :publish_on_save => should_publish
    )
    connectors.create(
        :page_version => draft.version,
        :connectable => connectable,
        :connectable_version => connectable.class.versioned? ? connectable.version : nil,
        :container => container)
  end
end

#after_build_new_version(new_version) ⇒ Object

Implements Versioning Callback.



145
146
147
148
149
150
151
152
# File 'app/models/cms/page.rb', line 145

def after_build_new_version(new_version)
  copy_connectors(
      :from_version_number => @copy_connectors_from_version || (new_version.version - 1),
      :to_version_number => new_version.version
  )
  @copy_connectors_from_version = nil
  true
end

#after_publishObject

Publish all



155
156
157
158
159
160
161
162
# File 'app/models/cms/page.rb', line 155

def after_publish
  self.reload # Get's the correct version number loaded
  self.connectors.for_page_version(self.version).order("position").to_a.each do |c|
    if c.connectable_type.constantize.publishable? && con = c.connectable
      con.publish
    end
  end
end

#append_leading_slash_to_pathObject



298
299
300
301
302
303
304
# File 'app/models/cms/page.rb', line 298

def append_leading_slash_to_path
  if path.blank?
    self.path = "/"
  elsif path[0, 1] != "/"
    self.path = "/#{path}"
  end
end

#assigned_toObject



404
405
406
# File 'app/models/cms/page.rb', line 404

def assigned_to
  current_task ? current_task.assigned_to : nil
end

#assigned_to?(user) ⇒ Boolean

Returns:

  • (Boolean)


408
409
410
# File 'app/models/cms/page.rb', line 408

def assigned_to?(user)
  assigned_to == user
end

#connectable_count_for_container(container) ⇒ Object

Returns the number of connectables in the given container for this version of this page



368
369
370
# File 'app/models/cms/page.rb', line 368

def connectable_count_for_container(container)
  connectors.for_page_version(version).in_container(container.to_s).count
end

#container_published?(container) ⇒ Boolean

Returns true if the block attached to each connector in the given container are published

Returns:

  • (Boolean)


361
362
363
364
365
# File 'app/models/cms/page.rb', line 361

def container_published?(container)
  connectors.for_page_version(draft.version).in_container(container.to_s).all? do |c|
    c.connectable_type.constantize.publishable? ? c.connectable.live? : true
  end
end

#contentsArray<ContentBlock>

Returns all content for the current page, excluding any deleted ones.

Returns:

  • (Array<ContentBlock>)


129
130
131
# File 'app/models/cms/page.rb', line 129

def contents
  current_connectors.map(&:connectable_with_deleted)
end

#copy_connectors(options = {}) ⇒ Object

Each time a page is updated, we need to copy all connectors associated with it forward, and save them.



166
167
168
169
170
171
172
173
174
175
176
177
178
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
# File 'app/models/cms/page.rb', line 166

def copy_connectors(options={})
  logger.debug { "Copying connectors from Page #{id} v#{options[:from_version_number]} to v#{options[:to_version_number]}." }

  c_found = connectors.for_page_version(options[:from_version_number]).order("#{Cms::Connector.table_name}.container, #{Cms::Connector.table_name}.position").to_a
  logger.debug { "Found connectors #{c_found}" }
  c_found.each do |c|

    # The connector won't have a connectable if it has been deleted
    # Also need to see if the draft has been deleted,
    # in which case we are in the process of deleting it
    if c.should_be_copied?
      logger.debug { "Connector id=>#{c.id} should be copied." }
      connectable = c.connectable_type.constantize.versioned? ? c.connectable.as_of_version(c.connectable_version) : c.connectable
      version = connectable.class.versioned? ? connectable.version : nil

      #If we are copying connectors from a previous version, that means we are reverting this page,
      #in which case we should create a new version of the block, and connect this page to that block.
      #If the connectable is versioned, the connector needs to reference the newly drafted connector
      #that is created during the revert_to method
      if @copy_connectors_from_version && connectable.class.versioned? && (connectable.version != connectable.draft.version)
        connectable = connectable.class.find(connectable.id)
        connectable.updated_by_page = self
        connectable.revert_to(c.connectable_version)
        version = connectable.class.versioned? ? connectable.draft.version : nil
      end

      logger.debug "When copying block #{connectable.inspect} version is '#{version}'"

      new_connector = connectors.create(
          :page_version => options[:to_version_number],
          :connectable => connectable,
          :connectable_version => version,
          :container => c.container,
          :position => c.position
      )
      logger.debug { "Built new connector #{new_connector}." }
    end
  end
  true
end

#current_connectors(container = nil) ⇒ Object

Return a list of all connectors for the current version of the page.

Parameters:

  • container (Symbol) (defaults to: nil)

    The name of the container to match (Optional - Return all)



135
136
137
138
139
140
141
142
# File 'app/models/cms/page.rb', line 135

def current_connectors(container=nil)
  @current_connectors ||= self.connectors.for_page_version(self.version)
  if (container)
    @current_connectors.select { |c| c.container.to_sym == container }
  else
    @current_connectors
  end
end

#current_taskObject



400
401
402
# File 'app/models/cms/page.rb', line 400

def current_task
  tasks.incomplete.first
end

#deletable?Boolean

Returns true if this page can be deleted or not.

Returns:

  • (Boolean)

    true if this page can be deleted or not.



384
385
386
# File 'app/models/cms/page.rb', line 384

def deletable?
  !home?
end

#delete_connectorsObject

Pages that get deleted should be ‘disconnected’ from any blocks they were associated with.



266
267
268
# File 'app/models/cms/page.rb', line 266

def delete_connectors
  connectors.for_page_version(version).to_a.each { |c| c.destroy }
end

#file_sizeObject

Pages have no size (for the purposes of FCKEditor)



278
279
280
# File 'app/models/cms/page.rb', line 278

def file_size
  "NA"
end

#home?Boolean

Returns true if this page is the home page of the site.

Returns:

  • (Boolean)

    true if this page is the home page of the site.



378
379
380
# File 'app/models/cms/page.rb', line 378

def home?
  path == "/"
end

#in_section?(section_or_section_name) ⇒ Boolean

Determines if a page is a descendant of a given Section.

Parameters:

  • section_or_section_name (String | Section)

Returns:

  • (Boolean)


342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'app/models/cms/page.rb', line 342

def in_section?(section_or_section_name)
  found = false
  ancestors.each do |a|
    if section_or_section_name.is_a?(String)
      if a.name == section_or_section_name
        found = true
        break
      end
    else
      if a == section_or_section_name
        found = true
        break
      end
    end
  end
  found
end

#landing_page?Boolean

Whether or not this page is considered the ‘landing’ page for its parent section. These ‘Overview’ pages will have the same path as their parent.

Returns:

  • (Boolean)


286
287
288
# File 'app/models/cms/page.rb', line 286

def landing_page?
  parent.path == path
end

#layout(version = :full) ⇒ Object

Return the layout used to render this page. Will be something like: ‘templates/subpage’

Parameters:

  • version (Symbol) (defaults to: :full)

    Valid values are :full and :mobile.



320
321
322
323
# File 'app/models/cms/page.rb', line 320

def layout(version = :full)
  folder = (version == :mobile) ? "mobile" : "templates"
  template_file_name && "#{folder}/#{layout_name}"
end

#layout_nameObject

Return the file name of the template



326
327
328
# File 'app/models/cms/page.rb', line 326

def layout_name
  template_file_name.split('.').first
end

#move_connector(connector, direction) ⇒ Object

Moves a specific connector up or down within its container for a page.



235
236
237
238
239
240
241
242
243
# File 'app/models/cms/page.rb', line 235

def move_connector(connector, direction)
  transaction do
    raise "Connector is nil" unless connector
    raise "Direction is nil" unless direction
    orientation = direction[/_/] ? "#{direction.sub('_', ' the ')} of" : "#{direction} within"
    update_attributes(:version_comment => "#{connector.connectable} was moved #{orientation} the '#{connector.container}' container", :publish_on_save => false)
    connectors.for_page_version(draft.version).like(connector).first.send("move_#{direction}")
  end
end

#name_with_section_pathObject



372
373
374
375
# File 'app/models/cms/page.rb', line 372

def name_with_section_path
  a = ancestors
  (a[1..a.size].map { |a| a.name } + [name]).join(" / ")
end

#page_titleObject



294
295
296
# File 'app/models/cms/page.rb', line 294

def page_title
  title.blank? ? name : title
end

#path_not_reservedObject



312
313
314
315
316
# File 'app/models/cms/page.rb', line 312

def path_not_reserved
  if Cms.reserved_paths.include?(path)
    errors.add(:path, "is invalid, '#{path}' a reserved path")
  end
end

#public?Boolean

Returns:

  • (Boolean)


290
291
292
# File 'app/models/cms/page.rb', line 290

def public?
  section ? section.public? : false
end

#remove_connector(connector) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'app/models/cms/page.rb', line 251

def remove_connector(connector)
  transaction do
    raise "Connector is nil" unless connector
    update_attributes(version_comment: "#{connector.connectable} was removed from the '#{connector.container}' container", publish_on_save: false)

    #The logic of this is to go ahead and let the container get copied forward, then delete the new connector
    if new_connector = connectors.for_page_version(draft.version).like(connector).first
      new_connector.destroy
    else
      raise "Error occurred while trying to remove connector #{connector.id}"
    end
  end
end

#remove_trailing_slash_from_pathObject

remove trailing slash, unless the path is only a slash. uses capture and substition because ruby regex engine does not support lookbehind



308
309
310
# File 'app/models/cms/page.rb', line 308

def remove_trailing_slash_from_path
  self.path.sub!(/(.+)\/+$/, '\1')
end

#revert_to(version) ⇒ Object

This is done to let copy_connectors know which version to pull from copy_connectors will get called later as an after_update callback



272
273
274
275
# File 'app/models/cms/page.rb', line 272

def revert_to(version)
  @copy_connectors_from_version = version
  super(version)
end

#templateObject

This will be nil if it is a file system based template



331
332
333
# File 'app/models/cms/page.rb', line 331

def template
  Cms::PageTemplate.find_by_file_name(template_file_name)
end

#template_nameObject



335
336
337
# File 'app/models/cms/page.rb', line 335

def template_name
  template_file_name && Cms::PageTemplate.display_name(template_file_name)
end

#top_level_sectionSection

This will return the “top level section” for this page, which is the section directly below the root (a.k.a My Site) that this page is in. If this page is in root, then this will return root.

Returns:

  • (Section)

    The first non-root ancestor if available, root otherwise.



393
394
395
396
397
398
# File 'app/models/cms/page.rb', line 393

def top_level_section
  # Cache the results of this since many projects will call it repeatly on current_page in menus.
  return @top_level_section if @top_level_section
  a = ancestors
  @top_level_section = (a.size > 0 && a[1]) ? a[1] : Cms::Section.root.first
end

#visibilitiesObject

Return a collection of the available visibility statuses this model will accept via #visibility=



413
414
415
# File 'app/models/cms/page.rb', line 413

def visibilities
  [['Public', :public], ['Archived', :archived], ['Hidden' , :hidden]]
end

#visibilityObject



417
418
419
420
421
422
423
424
425
# File 'app/models/cms/page.rb', line 417

def visibility
  if archived?
    :archived
  elsif hidden?
    :hidden
  else
    :public
  end
end

#visibility=(new_state) ⇒ Object



427
428
429
430
431
432
433
434
435
# File 'app/models/cms/page.rb', line 427

def visibility=(new_state)
  self.archived = false
  self.hidden = false
  if new_state.to_sym == :archived
    self.archived = true
  elsif new_state.to_sym == :hidden
    self.hidden = true
  end
end