browsercms 3.3.2 → 3.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/app/controllers/cms/content_block_controller.rb +2 -2
  2. data/app/controllers/cms/content_controller.rb +1 -1
  3. data/app/controllers/cms/section_nodes_controller.rb +6 -1
  4. data/app/controllers/cms/sections_controller.rb +1 -1
  5. data/app/helpers/cms/application_helper.rb +1 -1
  6. data/app/helpers/cms/content_block_helper.rb +27 -0
  7. data/app/helpers/cms/section_nodes_helper.rb +43 -5
  8. data/app/models/abstract_file_block.rb +17 -2
  9. data/app/models/attachment.rb +16 -34
  10. data/app/models/file_block.rb +0 -12
  11. data/app/models/image_block.rb +0 -12
  12. data/app/models/link.rb +4 -21
  13. data/app/models/page.rb +36 -35
  14. data/app/models/section.rb +82 -42
  15. data/app/models/section_node.rb +41 -24
  16. data/app/views/cms/blocks/index.html.erb +4 -4
  17. data/app/views/cms/file_blocks/_form.html.erb +1 -1
  18. data/app/views/cms/image_blocks/_form.html.erb +1 -1
  19. data/app/views/cms/section_nodes/_link.html.erb +6 -3
  20. data/app/views/cms/section_nodes/_node.html.erb +11 -2
  21. data/app/views/cms/section_nodes/_page.html.erb +13 -7
  22. data/app/views/cms/section_nodes/_section.html.erb +24 -8
  23. data/app/views/cms/section_nodes/index.html.erb +18 -6
  24. data/app/views/cms/shared/_pagination.html.erb +4 -4
  25. data/app/views/portlets/reset_password/render.html.erb +0 -2
  26. data/browsercms.gemspec +1 -4
  27. data/db/migrate/20100117144039_browsercms315.rb +94 -0
  28. data/lib/acts_as_list.rb +1 -1
  29. data/lib/browsercms.rb +3 -1
  30. data/lib/cms/addressable.rb +83 -0
  31. data/lib/cms/behaviors/attaching.rb +42 -24
  32. data/lib/cms/behaviors/connecting.rb +2 -1
  33. data/lib/cms/behaviors/publishing.rb +12 -3
  34. data/lib/cms/behaviors/versioning.rb +43 -24
  35. data/lib/cms/content_rendering_support.rb +3 -3
  36. data/lib/cms/error_pages.rb +8 -0
  37. data/lib/cms/version.rb +2 -2
  38. data/lib/generators/browser_cms/cms/cms_generator.rb +1 -0
  39. data/lib/generators/cms/upgrade_module/templates/GPL.txt +1 -1
  40. data/lib/tasks/data.rake +43 -0
  41. metadata +27 -8
  42. data/app/views/cms/section_nodes/_section_node.html.erb +0 -10
@@ -121,8 +121,8 @@ class Cms::ContentBlockController < Cms::BaseController
121
121
  def load_blocks
122
122
  options = {}
123
123
  if params[:section_id] && params[:section_id] != 'all'
124
- options[:include] = { :attachment => { :section_node => :section }}
125
- options[:conditions] = ["sections.id = ?", params[:section_id]]
124
+ options[:include] = { :attachment => :section_node }
125
+ options[:conditions] = ["section_nodes.ancestry = ?", Section.find(params[:section_id]).ancestry_path]
126
126
  end
127
127
  options[:page] = params[:page]
128
128
  options[:order] = model_class.default_order if model_class.respond_to?(:default_order)
@@ -90,7 +90,7 @@ class Cms::ContentController < Cms::ApplicationController
90
90
 
91
91
  def try_to_redirect
92
92
  if redirect = Redirect.find_by_from_path(@path)
93
- redirect_to redirect.to_path
93
+ redirect_to redirect.to_path, :status=>:moved_permanently
94
94
  end
95
95
  end
96
96
 
@@ -3,7 +3,12 @@ class Cms::SectionNodesController < Cms::BaseController
3
3
 
4
4
  def index
5
5
  @toolbar_tab = :sitemap
6
- @section = Section.root.first
6
+ @modifiable_sections = current_user.modifiable_sections
7
+ @public_sections = Group.guest.sections.all # Load once here so that every section doesn't need to.
8
+
9
+ @sitemap = Section.sitemap
10
+ @root_section_node = @sitemap.keys.first
11
+ @section = @root_section_node.node
7
12
  end
8
13
  def move_before
9
14
  move(:before)
@@ -16,7 +16,7 @@ class Cms::SectionsController < Cms::BaseController
16
16
  end
17
17
 
18
18
  def new
19
- @section = @parent.sections.build
19
+ @section = @parent.build_section
20
20
  @section.groups = @parent.groups
21
21
  end
22
22
 
@@ -23,7 +23,7 @@ module Cms
23
23
  def searchable_sections(selected = nil)
24
24
  root = Section.root.first
25
25
  options = [['All sections', 'all'], [root.name, root.id]]
26
- root.all_children_with_name.each { |s| options << [s.full_path, s.id] }
26
+ root.master_section_list.each { |s| options << [s.full_path, s.id] }
27
27
  options_for_select(options, selected.to_i)
28
28
  end
29
29
 
@@ -0,0 +1,27 @@
1
+ module Cms
2
+ module ContentBlockHelper
3
+
4
+
5
+ # Prints the <tr> for each block. Adds classes based on:
6
+ # * Name/id of the block
7
+ # * If a block is published/draft
8
+ # * If the user can edit/publish it
9
+ def block_row_tag(block)
10
+ cname = class_name_for(block)
11
+ can_modify = current_user.able_to_modify?(block)
12
+
13
+ options = {
14
+ :id => "#{cname}_#{block.id}",
15
+ :class => cname
16
+ }
17
+ options[:class] += block.class.publishable? && !block.published? ? ' draft' : ' published'
18
+ options[:class] += ' non-editable' unless can_modify && current_user.able_to?(:edit_content)
19
+ options[:class] += ' non-publishable' unless can_modify && current_user.able_to?(:publish_content)
20
+ tag "tr", options, true
21
+ end
22
+
23
+ def class_name_for(block)
24
+ block.class.name.underscore
25
+ end
26
+ end
27
+ end
@@ -1,13 +1,51 @@
1
1
  module Cms
2
2
  module SectionNodesHelper
3
- def section_icons(node)
4
-
5
- if (node.root? || node.parent.root? || node.parent.parent.root?)
6
- node.child_nodes.empty? ? image_tag("cms/sitemap/no_contents.png", :class => "no_folder_toggle large") : image_tag("cms/sitemap/gray_expand.png", :class => "folder_toggle large")
3
+
4
+ def access_status(section_node, public_sections)
5
+ access_icon = :unlocked
6
+ unless public_sections.include?(section_node)
7
+ access_icon = :locked
8
+ end
9
+ access_icon
10
+ end
11
+
12
+ def section_icons(section_node, children=[])
13
+ folder_style = ""
14
+ expander_image = "expand.png"
15
+ if top_level_section?(section_node)
16
+ folder_style = " large"
17
+ expander_image = "gray_expand.png"
18
+ end
19
+ if children.empty?
20
+ image_tag("cms/sitemap/no_contents.png", :class => "no_folder_toggle#{folder_style}")
7
21
  else
8
- node.child_nodes.empty? ? image_tag("cms/sitemap/no_contents.png", :class => "no_folder_toggle") : image_tag("cms/sitemap/expand.png", :class => "folder_toggle")
22
+ image_tag("cms/sitemap/#{expander_image}", :class => "folder_toggle#{folder_style}")
9
23
  end
10
24
  end
11
25
 
26
+ # Renders the ul for a given node (Page/Section/Link/etc)
27
+ # Default look:
28
+ # - First level pages/sections use 'big' icons
29
+ # - All non-first level items should be hidden.
30
+ def sitemap_ul_tag(node)
31
+ opts = {
32
+ :id => "section_node_#{node.section_node.id}",
33
+ :class => "section_node"
34
+ }
35
+ opts[:class] += " rootlet" if in_first_level?(node)
36
+ opts[:style] = "display: none" unless in_first_level?(node)
37
+ tag("ul", opts, true)
38
+ end
39
+
40
+ def in_first_level?(node)
41
+ node.section_node.depth == 1
42
+ end
43
+
44
+ private
45
+
46
+ def top_level_section?(node)
47
+ node.depth <= 2
48
+ end
49
+
12
50
  end
13
51
  end
@@ -4,8 +4,11 @@ class AbstractFileBlock < ActiveRecord::Base
4
4
 
5
5
  validates_presence_of :name
6
6
 
7
- scope :by_section, lambda { |section| { :include => {:attachment => :section_node }, :conditions => ["section_nodes.section_id = ?", section.id] } }
8
-
7
+ scope :by_section, lambda { |section| {
8
+ :include => {:attachment => :section_node },
9
+ :conditions => ["section_nodes.ancestry = ?", section.node.ancestry_path] }
10
+ }
11
+
9
12
  def path
10
13
  attachment_file_path
11
14
  end
@@ -14,4 +17,16 @@ class AbstractFileBlock < ActiveRecord::Base
14
17
  true
15
18
  end
16
19
 
20
+ def set_attachment_path
21
+ if @attachment_file_path && @attachment_file_path != attachment.file_path
22
+ attachment.file_path = @attachment_file_path
23
+ end
24
+ end
25
+
26
+ def set_attachment_section
27
+ if @attachment_section_id && @attachment_section_id != attachment.section
28
+ attachment.section_id = @attachment_section_id
29
+ end
30
+ end
31
+
17
32
  end
@@ -28,7 +28,6 @@ class Attachment < ActiveRecord::Base
28
28
  before_validation :extract_file_type_from_temp_file
29
29
  before_validation :extract_file_size_from_temp_file
30
30
  before_validation :set_file_location
31
- before_save :process_section
32
31
 
33
32
  after_save :write_temp_file_to_storage_location
34
33
  after_save :clear_ivars
@@ -36,41 +35,21 @@ class Attachment < ActiveRecord::Base
36
35
 
37
36
  #----- Associations ----------------------------------------------------------
38
37
 
38
+ include Addressable
39
+ include Addressable::DeprecatedPageAccessors
39
40
  has_one :section_node, :as => :node
41
+ alias :node :section_node
40
42
 
41
43
  #----- Validations -----------------------------------------------------------
42
44
 
43
45
  validates_presence_of :temp_file, :message => "You must upload a file", :on => :create
44
46
  validates_presence_of :file_path
45
47
  validates_uniqueness_of :file_path
46
- validates_presence_of :section_id
47
-
48
- #----- Virtual Attributes ----------------------------------------------------
49
-
50
- def section_id
51
- @section_id ||= section_node ? section_node.section_id : nil
52
- end
53
-
54
- def section_id=(section_id)
55
- if @section_id != section_id
56
- dirty!
57
- @section_id = section_id
58
- end
59
- end
60
-
61
- def section
62
- @section ||= section_node ? section_node.section : nil
63
- end
64
48
 
65
49
  def section=(section)
66
- logger.debug {"Attachment#section=(#{section})"}
67
- if @section != section
68
- dirty!
69
- @section_id = section ? section.id : nil
70
- @section = section
71
- end
50
+ dirty! if self.section != section
51
+ super(section)
72
52
  end
73
-
74
53
  #----- Callbacks Methods -----------------------------------------------------
75
54
 
76
55
  def make_dirty_if_temp_file
@@ -117,14 +96,17 @@ class Attachment < ActiveRecord::Base
117
96
  end
118
97
  end
119
98
 
120
- def process_section
121
- #logger.info "processing section, section_id => #{section_id}, section_node => #{section_node.inspect}"
122
- if section_node && !section_node.new_record? && section_node.section_id != section_id
123
- section_node.move_to_end(Section.find(section_id))
124
- else
125
- build_section_node(:node => self, :section_id => section_id)
126
- end
127
- end
99
+ #def process_section
100
+ # if section_node
101
+ # section_node.move_to_end(parent)
102
+ # #end
103
+ # #logger.info "processing section, section_id => #{section_id}, section_node => #{section_node.inspect}"
104
+ # #if section_node && !section_node.new_record? && section_node.section_id != section_id
105
+ # # section_node.move_to_end(Section.find(section_id))
106
+ # else
107
+ # build_section_node(:node => self, :parent => parent)
108
+ # end
109
+ #end
128
110
 
129
111
  def write_temp_file_to_storage_location
130
112
  unless temp_file.blank?
@@ -1,18 +1,6 @@
1
1
  class FileBlock < AbstractFileBlock
2
2
 
3
3
  acts_as_content_block :belongs_to_attachment => true, :taggable => true
4
-
5
- def set_attachment_file_path
6
- if @attachment_file_path && @attachment_file_path != attachment.file_path
7
- attachment.file_path = @attachment_file_path
8
- end
9
- end
10
-
11
- def set_attachment_section
12
- if @attachment_section_id && @attachment_section_id != attachment.section_id
13
- attachment.section_id = @attachment_section_id
14
- end
15
- end
16
4
 
17
5
  def self.display_name
18
6
  "File"
@@ -3,18 +3,6 @@ class ImageBlock < AbstractFileBlock
3
3
  acts_as_content_block :versioned => { :version_foreign_key => :file_block_id },
4
4
  :belongs_to_attachment => true, :taggable => true
5
5
 
6
- def set_attachment_file_path
7
- if @attachment_file_path && @attachment_file_path != attachment.file_path
8
- attachment.file_path = @attachment_file_path
9
- end
10
- end
11
-
12
- def set_attachment_section
13
- if @attachment_section_id && @attachment_section_id != attachment.section_id
14
- attachment.section_id = @attachment_section_id
15
- end
16
- end
17
-
18
6
  def self.display_name
19
7
  "Image"
20
8
  end
data/app/models/link.rb CHANGED
@@ -3,29 +3,12 @@ class Link < ActiveRecord::Base
3
3
 
4
4
  scope :named, lambda{|name| {:conditions => ['links.name = ?', name]}}
5
5
 
6
- has_one :section_node, :as => :node, :dependent => :destroy
7
-
6
+ has_one :section_node, :as => :node, :dependent => :destroy, :inverse_of => :node
7
+
8
8
  validates_presence_of :name
9
9
 
10
- def section_id
11
- section ? section.id : nil
12
- end
13
-
14
- def section
15
- section_node ? section_node.section : nil
16
- end
17
-
18
- def section_id=(sec_id)
19
- self.section = Section.find(sec_id)
20
- end
21
-
22
- def section=(sec)
23
- if section_node
24
- section_node.move_to_end(sec)
25
- else
26
- build_section_node(:node => self, :section => sec)
27
- end
28
- end
10
+ include Addressable
11
+ include Addressable::DeprecatedPageAccessors
29
12
 
30
13
  #needed by menu_helper
31
14
  def path
data/app/models/page.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  class Page < ActiveRecord::Base
2
-
2
+
3
+ def actual_path
4
+ path
5
+ end
6
+
3
7
  is_archivable
4
8
  flush_cache_on_change
5
9
  is_hideable
@@ -57,8 +61,12 @@ class Page < ActiveRecord::Base
57
61
  end
58
62
  }
59
63
 
60
- has_one :section_node, :as => :node, :dependent => :destroy
61
-
64
+ has_one :section_node, :as => :node, :dependent => :destroy, :inverse_of => :node
65
+
66
+
67
+ include Addressable
68
+ include Addressable::DeprecatedPageAccessors
69
+
62
70
  has_many :tasks
63
71
 
64
72
  before_validation :append_leading_slash_to_path, :remove_trailing_slash_from_path
@@ -123,7 +131,7 @@ class Page < ActiveRecord::Base
123
131
  :page_version => options[:to_version_number],
124
132
  :connectable => connectable,
125
133
  :connectable_version => version,
126
- :container => c.container,
134
+ :container => c.container,
127
135
  :position => c.position
128
136
  )
129
137
  logger.debug {"Built new connector #{new_connector}."}
@@ -200,26 +208,6 @@ class Page < ActiveRecord::Base
200
208
  "?"
201
209
  end
202
210
 
203
- def section_id
204
- section ? section.id : nil
205
- end
206
-
207
- def section
208
- section_node ? section_node.section : nil
209
- end
210
-
211
- def section_id=(sec_id)
212
- self.section = Section.find(sec_id)
213
- end
214
-
215
- def section=(sec)
216
- if section_node
217
- section_node.move_to_end(sec)
218
- else
219
- build_section_node(:node => self, :section => sec)
220
- end
221
- end
222
-
223
211
  def public?
224
212
  section ? section.public? : false
225
213
  end
@@ -261,16 +249,25 @@ class Page < ActiveRecord::Base
261
249
  template_file_name && PageTemplate.display_name(template_file_name)
262
250
  end
263
251
 
264
- def ancestors
265
- section_node.ancestors
266
- end
267
-
252
+ # Determines if a page is a descendant of a given Section.
253
+ #
254
+ # @param [String | Section] section_or_section_name
268
255
  def in_section?(section_or_section_name)
269
- sec = section_or_section_name.is_a?(String) ?
270
- Section.first(:conditions => {:name => section_or_section_name}) :
271
- section_or_section_name
272
- fn = lambda{|s| s ? (s == sec || fn.call(s.parent)) : false}
273
- fn.call(section)
256
+ found = false
257
+ ancestors.each do |a|
258
+ if section_or_section_name.is_a?(String)
259
+ if a.name == section_or_section_name
260
+ found = true
261
+ break
262
+ end
263
+ else
264
+ if a == section_or_section_name
265
+ found = true
266
+ break
267
+ end
268
+ end
269
+ end
270
+ found
274
271
  end
275
272
 
276
273
  #Returns true if the block attached to each connector in the given container are published
@@ -294,12 +291,16 @@ class Page < ActiveRecord::Base
294
291
  (a[1..a.size].map{|a| a.name} + [name]).join(" / ")
295
292
  end
296
293
 
297
- # This will return the "top level section" for a page, which is the section directly
294
+ # This will return the "top level section" for this page, which is the section directly
298
295
  # below the root (a.k.a My Site) that this page is in. If this page is in root,
299
296
  # then this will return root.
297
+ #
298
+ # @return [Section] The first non-root ancestor if available, root otherwise.
300
299
  def top_level_section
300
+ # Cache the results of this since many projects will call it repeatly on current_page in menus.
301
+ return @top_level_section if @top_level_section
301
302
  a = ancestors
302
- (a.size > 0 && ancestors[1]) ? ancestors[1] : Section.root.first
303
+ @top_level_section = (a.size > 0 && a[1]) ? a[1] : Section.root.first
303
304
  end
304
305
 
305
306
  def current_task
@@ -3,14 +3,15 @@ class Section < ActiveRecord::Base
3
3
  flush_cache_on_change
4
4
 
5
5
  #The node that links this section to its parent
6
- has_one :node, :class_name => "SectionNode", :as => :node, :dependent => :destroy
6
+ has_one :section_node, :class_name => "SectionNode", :as => :node, :inverse_of => :node
7
7
 
8
- #The nodes that link this section to its children
9
- has_many :child_nodes, :class_name => "SectionNode"
10
- has_many :child_sections, :class_name => "SectionNode", :conditions => ["node_type = ?", "Section"], :order => 'section_nodes.position'
8
+ include Addressable
9
+ include Addressable::NodeAccessors
11
10
 
12
- has_many :pages, :through => :child_nodes, :source => :node, :source_type => 'Page', :order => 'section_nodes.position'
13
- has_many :sections, :through => :child_nodes, :source => :node, :source_type => 'Section', :order => 'section_nodes.position'
11
+ # Cannot use dependent => :destroy to do this. Ancestry's callbacks trigger before the before_destroy callback.
12
+ # So sections would always get deleted since deletable? would return true
13
+ after_destroy :destroy_node
14
+ before_destroy :deletable?
14
15
 
15
16
  has_many :group_sections
16
17
  has_many :groups, :through => :group_sections
@@ -25,55 +26,81 @@ class Section < ActiveRecord::Base
25
26
  scope :with_path, lambda{|path| {:conditions => ['sections.path = ?', path]}}
26
27
 
27
28
  validates_presence_of :name, :path
28
- #validates_presence_of :parent_id, :if => Proc.new {root.count > 0}, :message => "section is required"
29
29
 
30
30
  # Disabling '/' in section name for interoperability with FCKEditor file browser
31
31
  validates_format_of :name, :with => /\A[^\/]*\Z/, :message => "cannot contain '/'"
32
32
 
33
33
  validate :path_not_reserved
34
34
 
35
- before_destroy :deletable?
36
-
37
35
  attr_accessor :full_path
38
36
 
39
- def visible_child_nodes(options={})
40
- children = child_nodes.of_type(["Section", "Page", "Link"]).all(:order => 'section_nodes.position')
41
- visible_children = children.select{|sn| sn.visible?}
42
- options[:limit] ? visible_children[0...options[:limit]] : visible_children
37
+ delegate :ancestry_path, :to => :node
38
+
39
+ def ancestry
40
+ self.node.ancestry
43
41
  end
44
42
 
45
- def all_children_with_name
46
- child_sections.map do |s|
47
- if s.node
48
- s.node.full_path = root? ? s.node.name : "#{name} / #{s.node.name}"
49
- [s.node] << s.node.all_children_with_name
50
- end
51
- end.flatten.compact
43
+ before_validation :ensure_section_node_exists
44
+
45
+ def ensure_section_node_exists
46
+ unless node
47
+ self.node = build_section_node
48
+ end
52
49
  end
53
50
 
54
- def parent_id
55
- parent ? parent.id : nil
51
+ # Returns a list of all children which are sections.
52
+ # @return [Array<Section>]
53
+ def sections
54
+ child_nodes.of_type("Section").fetch_nodes.in_order.collect do |section_node|
55
+ section_node.node
56
+ end
56
57
  end
57
58
 
58
- def parent
59
- node ? node.section : nil
59
+ alias :child_sections :sections
60
+
61
+ # Since #sections isn't an association anymore, callers can use this rather than #sections.build
62
+ def build_section
63
+ Section.new(:parent=>self)
60
64
  end
61
65
 
62
- def parent_id=(sec_id)
63
- self.parent = Section.find(sec_id)
66
+ # Used by the sitemap to find children to iterate over.
67
+ def child_nodes
68
+ self.node.children
64
69
  end
65
70
 
66
- def parent=(sec)
67
- if node
68
- node.move_to_end(sec)
69
- else
70
- build_node(:node => self, :section => sec)
71
+ def pages
72
+ child_pages = self.node.children.collect do |section_node|
73
+ section_node.node if section_node.page?
71
74
  end
75
+ child_pages.compact
72
76
  end
73
77
 
74
- def ancestors(options={})
75
- ancs = node ? node.ancestors : []
76
- options[:include_self] ? ancs + [self] : ancs
78
+ def self.sitemap
79
+ SectionNode.of_type(["Page", "Link", "Section"]).fetch_nodes.arrange(:order=>:position)
80
+ end
81
+
82
+ def visible_child_nodes(options={})
83
+ children = child_nodes.of_type(["Section", "Page", "Link"]).fetch_nodes.in_order.all
84
+ visible_children = children.select { |sn| sn.visible? }
85
+ options[:limit] ? visible_children[0...options[:limit]] : visible_children
86
+ end
87
+
88
+
89
+ # Returns a complete list of all sections that are desecendants of this sections, in order, as a single flat list.
90
+ # Used by Section selectors where users have to pick a single section from a complete list of all sections.
91
+ def master_section_list
92
+ sections.map do |section|
93
+ section.full_path = root? ? section.name : "#{name} / #{section.name}"
94
+ [section] << section.master_section_list
95
+ end.flatten.compact
96
+ end
97
+
98
+ def parent_id
99
+ parent ? parent.id : nil
100
+ end
101
+
102
+ def parent_id=(sec_id)
103
+ self.parent = Section.find(sec_id)
77
104
  end
78
105
 
79
106
  def with_ancestors(options = {})
@@ -94,33 +121,46 @@ class Section < ActiveRecord::Base
94
121
  end
95
122
 
96
123
  def empty?
97
- child_nodes.reject{|n| n.orphaned?}.empty?
124
+ child_nodes.empty?
98
125
  end
99
126
 
127
+ # Callback to determine if this section can be deleted.
100
128
  def deletable?
101
129
  !root? && empty?
102
130
  end
103
131
 
132
+ # Callback to clean up related nodes
133
+ def destroy_node
134
+ node.destroy
135
+ end
136
+
104
137
  def editable_by_group?(group)
105
138
  group.editable_by_section(self)
106
139
  end
107
140
 
108
141
  def status
109
- public? ? :unlocked : :locked
142
+ @status ||= public? ? :unlocked : :locked
110
143
  end
111
144
 
145
+ # Used by the file browser to look up a section by the combined names as a path.
146
+ # i.e. /A/B/
147
+ # @return [Section] nil if not found
112
148
  def self.find_by_name_path(name_path)
113
- section = Section.root.first
114
- children = name_path.split("/")[1..-1] || []
115
- children.each do |name|
116
- section = section.sections.first(:conditions => {:name => name})
149
+ current_section = Section.root.first
150
+ path_names = name_path.split("/")[1..-1] || []
151
+
152
+ # This implementation is very slow as it has to loop over the entire tree in memory to match each name element.
153
+ path_names.each do |name|
154
+ current_section.sections.each do |s|
155
+ current_section = s if s.name == name
156
+ end
117
157
  end
118
- section
158
+ current_section
119
159
  end
120
160
 
121
161
  #The first page that is a decendent of this section
122
162
  def first_page_or_link
123
- section_node = child_nodes.of_type(['Link', 'Page']).first(:order => "section_nodes.position")
163
+ section_node = child_nodes.of_type(['Link', 'Page']).fetch_nodes.in_order.first
124
164
  return section_node.node if section_node
125
165
  sections.each do |s|
126
166
  node = s.first_page_or_link