refinerycms-pages 2.1.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/refinery/admin/page_parts_controller.rb +6 -1
  3. data/app/controllers/refinery/admin/pages_controller.rb +53 -45
  4. data/app/controllers/refinery/pages/admin/preview_controller.rb +12 -3
  5. data/app/controllers/refinery/pages_controller.rb +12 -12
  6. data/app/helpers/refinery/admin/pages_helper.rb +5 -4
  7. data/app/helpers/refinery/pages/content_pages_helper.rb +6 -1
  8. data/app/models/refinery/page.rb +115 -141
  9. data/app/models/refinery/page_part.rb +32 -7
  10. data/app/presenters/refinery/pages/content_presenter.rb +7 -5
  11. data/app/presenters/refinery/pages/menu_presenter.rb +41 -15
  12. data/app/presenters/refinery/pages/page_part_section_presenter.rb +1 -7
  13. data/app/presenters/refinery/pages/section_presenter.rb +2 -6
  14. data/app/views/refinery/admin/pages/_actions.html.erb +4 -13
  15. data/app/views/refinery/admin/pages/_form.html.erb +7 -10
  16. data/app/views/refinery/admin/pages/_form_advanced_options.html.erb +5 -3
  17. data/app/views/refinery/admin/pages/_form_extra_fields_for_more_options.html.erb +1 -0
  18. data/app/views/refinery/admin/pages/_form_new_page_parts.html.erb +8 -0
  19. data/app/views/refinery/admin/pages/_form_page_parts.html.erb +10 -21
  20. data/app/views/refinery/admin/pages/_page.html.erb +31 -31
  21. data/app/views/refinery/admin/pages/_page_part_field.html.erb +2 -1
  22. data/app/views/refinery/admin/pages/_records.html.erb +3 -3
  23. data/app/views/refinery/admin/pages/_save_and_continue_callback.html.erb +1 -0
  24. data/app/views/refinery/admin/pages/index.html.erb +2 -4
  25. data/app/views/refinery/admin/pages_dialogs/link_to.html.erb +1 -1
  26. data/config/locales/bg.yml +1 -2
  27. data/config/locales/ca.yml +85 -0
  28. data/config/locales/cs.yml +13 -3
  29. data/config/locales/da.yml +1 -2
  30. data/config/locales/de.yml +0 -1
  31. data/config/locales/el.yml +41 -29
  32. data/config/locales/en.yml +2 -2
  33. data/config/locales/es.yml +2 -4
  34. data/config/locales/fi.yml +1 -4
  35. data/config/locales/fr.yml +2 -2
  36. data/config/locales/hu.yml +1 -2
  37. data/config/locales/it.yml +15 -16
  38. data/config/locales/ja.yml +1 -3
  39. data/config/locales/ko.yml +1 -4
  40. data/config/locales/lt.yml +1 -3
  41. data/config/locales/lv.yml +0 -2
  42. data/config/locales/nb.yml +1 -4
  43. data/config/locales/nl.yml +1 -2
  44. data/config/locales/pl.yml +1 -13
  45. data/config/locales/pt-BR.yml +1 -3
  46. data/config/locales/pt.yml +1 -2
  47. data/config/locales/rs.yml +1 -3
  48. data/config/locales/ru.yml +8 -5
  49. data/config/locales/sk.yml +1 -2
  50. data/config/locales/sl.yml +1 -3
  51. data/config/locales/sv.yml +1 -3
  52. data/config/locales/tr.yml +1 -2
  53. data/config/locales/uk.yml +1 -5
  54. data/config/locales/vi.yml +1 -3
  55. data/config/locales/zh-CN.yml +1 -4
  56. data/config/locales/zh-TW.yml +1 -3
  57. data/config/routes.rb +16 -16
  58. data/db/migrate/20100913234708_create_refinerycms_pages_schema.rb +28 -11
  59. data/db/migrate/20140105190324_add_custom_slug_to_refinery_pages.rb +20 -0
  60. data/db/migrate/20150130044643_add_slug_to_refinery_page_parts.rb +6 -0
  61. data/db/migrate/20150720155305_update_slug_and_title_in_refinery_page_parts.rb +13 -0
  62. data/db/seeds.rb +42 -36
  63. data/lib/generators/refinery/pages/templates/config/initializers/refinery/pages.rb.erb +12 -0
  64. data/lib/refinery/pages.rb +4 -3
  65. data/lib/refinery/pages/admin/instance_methods.rb +3 -3
  66. data/lib/refinery/pages/configuration.rb +7 -1
  67. data/lib/refinery/pages/engine.rb +19 -18
  68. data/lib/refinery/pages/finder.rb +179 -0
  69. data/lib/refinery/pages/instance_methods.rb +3 -14
  70. data/lib/refinery/pages/tab.rb +2 -2
  71. data/lib/refinery/pages/types.rb +1 -1
  72. data/lib/refinery/pages/url.rb +15 -3
  73. data/license.md +1 -1
  74. data/refinerycms-pages.gemspec +8 -5
  75. data/spec/controllers/refinery/admin/pages_controller_spec.rb +53 -0
  76. data/spec/controllers/refinery/pages_controller_spec.rb +1 -1
  77. data/spec/factories/pages.rb +1 -1
  78. data/spec/features/refinery/admin/pages_spec.rb +274 -290
  79. data/spec/features/refinery/pages_spec.rb +123 -138
  80. data/spec/helpers/refinery/pages/admin/pages_helper_spec.rb +15 -11
  81. data/spec/helpers/refinery/pages/content_pages_helper_spec.rb +11 -11
  82. data/spec/lib/generators/refinery/pages/pages_generator_spec.rb +1 -1
  83. data/spec/lib/pages_spec.rb +2 -2
  84. data/spec/lib/refinery/pages/tab_spec.rb +9 -9
  85. data/spec/lib/refinery/pages/url_spec.rb +12 -12
  86. data/spec/models/refinery/page_finder_spec.rb +72 -0
  87. data/spec/models/refinery/page_menu_spec.rb +107 -0
  88. data/spec/models/refinery/page_meta_data_spec.rb +49 -0
  89. data/spec/models/refinery/page_part_spec.rb +67 -0
  90. data/spec/models/refinery/page_spec.rb +16 -534
  91. data/spec/models/refinery/page_url_spec.rb +320 -0
  92. data/spec/presenters/refinery/pages/content_page_presenter_spec.rb +9 -9
  93. data/spec/presenters/refinery/pages/content_presenter_spec.rb +20 -20
  94. data/spec/presenters/refinery/pages/menu_presenter_spec.rb +44 -6
  95. data/spec/presenters/refinery/pages/page_part_section_presenter_spec.rb +12 -12
  96. data/spec/presenters/refinery/pages/section_presenter_spec.rb +22 -22
  97. data/spec/presenters/refinery/pages/title_section_presenter_spec.rb +4 -4
  98. data/spec/support/refinery/pages/caching_helpers.rb +2 -2
  99. metadata +55 -25
  100. data/app/helpers/refinery/admin/page_parts_helper.rb +0 -6
  101. data/app/helpers/refinery/admin/pages_dialogs_helper.rb +0 -6
  102. data/app/sweepers/refinery/pages/page_sweeper.rb +0 -29
  103. data/lib/refinery/pages/caching.rb +0 -60
  104. data/spec/lib/refinery/pages/caching_spec.rb +0 -90
  105. data/spec/support/refinery/pages/caching.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ca74af9b5248a8313eba585323664f7421241c9
4
- data.tar.gz: a6940067a4a5686a4045cea92e156185cb2ba370
3
+ metadata.gz: 2bdcbfb6ced22f015c509108b4cdf43b28a2fb99
4
+ data.tar.gz: f1c3faf991e0c23fa346ed0461d5cf3759139bb0
5
5
  SHA512:
6
- metadata.gz: a2b2acb0803208475af177019dc732e90ab5c29c6ea16ba8113bfe8c972f2b2918bed991de0bfbdec5c1b16dbb54b04b6c58ffb17f7cda8d38dc515f3216bdee
7
- data.tar.gz: fd54a6aaad887e98d79ce2485ba77d53294b7f7397cb2ee2be1da52182c05ce5ef35b80a0f93a01edc1fb86a690b7153b9f5627fd273828f1dc3d87efb0fc93b
6
+ metadata.gz: 7dbd0c97774895a794dd88fd3114f8d601ebfca7de61771b9b60714b7614a4482511bf4e123da675eac832802c222a1539013c46806dd86ea575e7cbebfe102b
7
+ data.tar.gz: fd285907905d48ccbeaaacbebe163f5d101d25b5198c347ba2a427ee9c123d1541f362afeb8d2eb42ab0a6c97ca1baf6aa8511adababa9e0bdddf42522b63f54
@@ -4,7 +4,7 @@ module Refinery
4
4
 
5
5
  def new
6
6
  render :partial => '/refinery/admin/pages/page_part_field', :locals => {
7
- :part => ::Refinery::PagePart.new(:title => params[:title], :body => params[:body]),
7
+ :part => ::Refinery::PagePart.new(new_page_part_params),
8
8
  :new_part => true,
9
9
  :part_index => params[:part_index]
10
10
  }
@@ -21,6 +21,11 @@ module Refinery
21
21
  end
22
22
  end
23
23
 
24
+ protected
25
+ def new_page_part_params
26
+ params.permit(:title, :slug, :body)
27
+ end
28
+
24
29
  end
25
30
  end
26
31
  end
@@ -1,22 +1,18 @@
1
1
  module Refinery
2
2
  module Admin
3
3
  class PagesController < Refinery::AdminController
4
- include Pages::InstanceMethods
5
- cache_sweeper Pages::PageSweeper
4
+ prepend Pages::InstanceMethods
6
5
 
7
6
  crudify :'refinery/page',
8
- :order => "lft ASC",
9
7
  :include => [:translations, :children],
10
8
  :paging => false
11
9
 
12
- before_filter :load_valid_templates, :only => [:edit, :new, :create]
13
- before_filter :restrict_access, :only => [:create, :update, :update_positions, :destroy]
14
- after_filter proc { Pages::Caching.new().expire! }, :only => :update_positions
10
+ helper_method :valid_layout_templates, :valid_view_templates
15
11
 
16
12
  def new
17
- @page = Page.new(params.except(:controller, :action, :switch_locale))
13
+ @page = Page.new(new_page_params)
18
14
  Pages.default_parts_for(@page).each_with_index do |page_part, index|
19
- @page.parts << PagePart.new(:title => page_part, :position => index)
15
+ @page.parts << PagePart.new(:title => page_part, :slug => page_part, :position => index)
20
16
  end
21
17
  end
22
18
 
@@ -26,43 +22,38 @@ module Refinery
26
22
  end
27
23
 
28
24
  def update
29
- if @page.update_attributes(params[:page])
30
- flash.notice = t(
31
- 'refinery.crudify.updated',
32
- :what => "'#{@page.title}'"
33
- )
34
-
35
- unless from_dialog?
36
- unless params[:continue_editing] =~ /true|on|1/
37
- redirect_back_or_default(refinery.admin_pages_path)
38
- else
39
- unless request.xhr?
40
- redirect_to :back
41
- else
42
- render :partial => 'save_and_continue_callback', :locals => {
43
- :new_refinery_page_path => refinery.admin_page_path(@page.nested_url),
44
- :new_page_path => refinery.pages_admin_preview_page_path(@page.nested_url)
45
- }
46
- end
47
- end
48
- else
25
+ if @page.update_attributes(page_params)
26
+ flash.notice = t('refinery.crudify.updated', what: "'#{@page.title}'")
27
+
28
+ if from_dialog?
49
29
  self.index
50
30
  @dialog_successful = true
51
31
  render :index
32
+ else
33
+ if params[:continue_editing] =~ /true|on|1/
34
+ if request.xhr?
35
+ render partial: 'save_and_continue_callback',
36
+ locals: save_and_continue_locals(@page)
37
+ else
38
+ redirect_to :back
39
+ end
40
+ else
41
+ redirect_back_or_default(refinery.admin_pages_path)
42
+ end
52
43
  end
53
44
  else
54
- unless request.xhr?
55
- render :action => 'edit'
56
- else
45
+ if request.xhr?
57
46
  render :partial => '/refinery/admin/error_messages', :locals => {
58
47
  :object => @page,
59
48
  :include_object_name => true
60
49
  }
50
+ else
51
+ render 'edit'
61
52
  end
62
53
  end
63
54
  end
64
55
 
65
- protected
56
+ protected
66
57
 
67
58
  def after_update_positions
68
59
  find_all_pages
@@ -70,12 +61,12 @@ module Refinery
70
61
  end
71
62
 
72
63
  def find_page
73
- @page = Page.find_by_path_or_id(params[:path], params[:id])
64
+ @page = Page.find_by_path_or_id!(params[:path], params[:id])
74
65
  end
75
66
  alias_method :page, :find_page
76
67
 
77
68
  # We can safely assume ::Refinery::I18n is defined because this method only gets
78
- # Invoked when the before_filter from the plugin is run.
69
+ # Invoked when the before_action from the plugin is run.
79
70
  def globalize!
80
71
  return super unless action_name.to_s == 'index'
81
72
 
@@ -87,23 +78,40 @@ module Refinery
87
78
  end
88
79
  end
89
80
 
90
- def load_valid_templates
91
- @valid_layout_templates = Pages.layout_template_whitelist &
92
- Pages.valid_templates('app', 'views', '{layouts,refinery/layouts}', '*html*')
81
+ def valid_layout_templates
82
+ Pages.layout_template_whitelist & Pages.valid_templates(*Pages.layout_templates_pattern)
83
+ end
84
+
85
+ def valid_view_templates
86
+ Pages.valid_templates(*Pages.view_templates_pattern)
87
+ end
93
88
 
94
- @valid_view_templates = Pages.valid_templates('app', 'views', '{pages,refinery/pages}', '*html*')
89
+ def page_params
90
+ params.require(:page).permit(permitted_page_params)
95
91
  end
96
92
 
97
- def restrict_access
98
- if current_refinery_user.has_role?(:translator) && !current_refinery_user.has_role?(:superuser) &&
99
- (params[:switch_locale].blank? || params[:switch_locale] == Refinery::I18n.default_frontend_locale.to_s)
100
- flash[:error] = t('translator_access', :scope => 'refinery.admin.pages')
101
- redirect_to refinery.admin_pages_path
102
- end
93
+ def new_page_params
94
+ params.permit(:parent_id, :view_template, :layout_template)
95
+ end
96
+
97
+ private
103
98
 
104
- return true
99
+ def permitted_page_params
100
+ [
101
+ :browser_title, :draft, :link_url, :menu_title, :meta_description,
102
+ :parent_id, :skip_to_first_child, :show_in_menu, :title, :view_template,
103
+ :layout_template, :custom_slug, parts_attributes: [:id, :title, :slug, :body, :position]
104
+ ]
105
105
  end
106
106
 
107
+ def save_and_continue_locals(page)
108
+ nested_url = page.nested_url
109
+ {
110
+ new_refinery_edit_page_path: refinery.admin_edit_page_path(nested_url),
111
+ new_refinery_page_path: refinery.admin_page_path(nested_url),
112
+ new_page_path: refinery.pages_admin_preview_page_path(nested_url)
113
+ }
114
+ end
107
115
  end
108
116
  end
109
117
  end
@@ -8,7 +8,7 @@ module Refinery
8
8
  include Refinery::Admin::BaseController
9
9
  include Pages::RenderOptions
10
10
 
11
- skip_before_filter :error_404, :set_canonical
11
+ skip_before_action :error_404, :set_canonical
12
12
 
13
13
  layout :layout
14
14
 
@@ -17,6 +17,7 @@ module Refinery
17
17
  end
18
18
 
19
19
  protected
20
+
20
21
  def admin?
21
22
  false
22
23
  end
@@ -24,10 +25,10 @@ module Refinery
24
25
  def find_page
25
26
  if @page = Refinery::Page.find_by_path_or_id(params[:path], params[:id])
26
27
  # Preview existing pages
27
- @page.attributes = params[:page]
28
+ @page.attributes = page_params
28
29
  elsif params[:page]
29
30
  # Preview a non-persisted page
30
- @page = Page.new params[:page]
31
+ @page = Page.new page_params
31
32
  end
32
33
  end
33
34
  alias_method :page, :find_page
@@ -35,6 +36,14 @@ module Refinery
35
36
  def layout
36
37
  'application'
37
38
  end
39
+
40
+ def page_params
41
+ params.require(:page).permit(
42
+ :browser_title, :draft, :link_url, :menu_title, :meta_description,
43
+ :parent_id, :skip_to_first_child, :show_in_menu, :title, :view_template,
44
+ :layout_template, parts_attributes: [:id, :title, :body, :position]
45
+ )
46
+ end
38
47
  end
39
48
  end
40
49
  end
@@ -2,11 +2,11 @@ module Refinery
2
2
  class PagesController < ::ApplicationController
3
3
  include Pages::RenderOptions
4
4
 
5
- before_filter :find_page, :set_canonical
6
- before_filter :error_404, :unless => :current_user_can_view_page?
5
+ before_action :find_page, :set_canonical
6
+ before_action :error_404, :unless => :current_user_can_view_page?
7
7
 
8
8
  # Save whole Page after delivery
9
- after_filter :write_cache?
9
+ after_action :write_cache?
10
10
 
11
11
  # This action is usually accessed with the root path, normally '/'
12
12
  def home
@@ -53,15 +53,14 @@ module Refinery
53
53
  end
54
54
 
55
55
  def should_redirect_to_friendly_url?
56
- requested_friendly_id != page.friendly_id || ::Refinery::Pages.scope_slug_by_parent && params[:path].present? && params[:path].match(page.root.slug).nil?
56
+ requested_friendly_id != page.friendly_id || (
57
+ ::Refinery::Pages.scope_slug_by_parent &&
58
+ params[:path].present? && params[:path].match(page.root.slug).nil?
59
+ )
57
60
  end
58
61
 
59
62
  def current_user_can_view_page?
60
- page.live? || current_refinery_user_can_access?("refinery_pages")
61
- end
62
-
63
- def current_refinery_user_can_access?(plugin)
64
- refinery_user? && current_refinery_user.authorized_plugins.include?(plugin)
63
+ page.live? || authorisation_manager.allow?(:plugin, "refinery_pages")
65
64
  end
66
65
 
67
66
  def first_live_child
@@ -71,9 +70,9 @@ module Refinery
71
70
  def find_page(fallback_to_404 = true)
72
71
  @page ||= case action_name
73
72
  when "home"
74
- Refinery::Page.where(:link_url => '/').first
73
+ Refinery::Page.find_by(link_url: '/')
75
74
  when "show"
76
- Refinery::Page.find_by_path_or_id(params[:path], params[:id])
75
+ Refinery::Page.friendly.find_by_path_or_id(params[:path], params[:id])
77
76
  end
78
77
  @page || (error_404 if fallback_to_404)
79
78
  end
@@ -85,7 +84,8 @@ module Refinery
85
84
  end
86
85
 
87
86
  def write_cache?
88
- if Refinery::Pages.cache_pages_full && !refinery_user?
87
+ # Don't cache the page with the site bar showing.
88
+ if Refinery::Pages.cache_pages_full && !authorisation_manager.allow?(:read, :site_bar)
89
89
  cache_page(response.body, File.join('', 'refinery', 'cache', 'pages', request.path).to_s)
90
90
  end
91
91
  end
@@ -3,12 +3,12 @@ module Refinery
3
3
  module PagesHelper
4
4
  def parent_id_nested_set_options(current_page)
5
5
  pages = []
6
- nested_set_options(::Refinery::Page, current_page) {|page| pages << page}
6
+ nested_set_options(::Refinery::Page, current_page) { |page| pages << page}
7
7
  # page.title needs the :translations association, doing something like
8
8
  # nested_set_options(::Refinery::Page.includes(:translations), page) doesn't work, yet.
9
9
  # See https://github.com/collectiveidea/awesome_nested_set/pull/123
10
- ActiveRecord::Associations::Preloader.new(pages, :translations).run
11
- pages.map {|page| ["#{'-' * page.level} #{page.title}", page.id]}
10
+ ActiveRecord::Associations::Preloader.new.preload(pages, :translations)
11
+ pages.map { |page| ["#{'-' * page.level} #{page.title}", page.id]}
12
12
  end
13
13
 
14
14
  def template_options(template_type, current_page)
@@ -50,8 +50,9 @@ module Refinery
50
50
  # We show the title from the next available locale
51
51
  # if there is no title for the current locale
52
52
  def page_title_with_translations(page)
53
- page.title.presence || page.translations.detect {|t| t.title.present?}.title
53
+ page.title.presence || page.translations.detect { |t| t.title.present?}.title
54
54
  end
55
+
55
56
  end
56
57
  end
57
58
  end
@@ -18,9 +18,14 @@ module Refinery
18
18
  # so avoid common layout names such as :header, :footer, etc.
19
19
  def render_content_presenter(content_page, options = {})
20
20
  content_page.hide_sections(options[:hide_sections]) if options[:hide_sections]
21
- content_page.fetch_template_overrides {|section_id| content_for(section_id)}
21
+ content_page.fetch_template_overrides { |section_id| content_for(section_id)}
22
22
  content_page.to_html(options[:can_use_fallback])
23
23
  end
24
+
25
+ # Compiles the default menu.
26
+ def refinery_menu_pages
27
+ Refinery::Menu.new Refinery::Page.fast_menu
28
+ end
24
29
  end
25
30
  end
26
31
  end
@@ -2,6 +2,7 @@
2
2
  require 'friendly_id'
3
3
  require 'refinery/core/base_model'
4
4
  require 'refinery/pages/url'
5
+ require 'refinery/pages/finder'
5
6
 
6
7
  module Refinery
7
8
  class Page < Core::BaseModel
@@ -11,18 +12,35 @@ module Refinery
11
12
 
12
13
  class Translation
13
14
  is_seo_meta
14
- attr_accessible *::SeoMeta.attributes.keys, :locale
15
+
16
+ def self.seo_fields
17
+ ::SeoMeta.attributes.keys.map{ |a| [a, :"#{a}="]}.flatten
18
+ end
15
19
  end
16
20
 
17
- # Delegate SEO Attributes to globalize translation
18
- seo_fields = ::SeoMeta.attributes.keys.map{|a| [a, :"#{a}="]}.flatten
19
- delegate(*(seo_fields << {:to => :translation}))
21
+ class FriendlyIdOptions
22
+ def self.options
23
+ # Docs for friendly_id https://github.com/norman/friendly_id
24
+ friendly_id_options = {
25
+ use: [:reserved],
26
+ reserved_words: Refinery::Pages.friendly_id_reserved_words
27
+ }
28
+ if ::Refinery::Pages.scope_slug_by_parent
29
+ friendly_id_options[:use] << :scoped
30
+ friendly_id_options.merge!(scope: :parent)
31
+ end
32
+ friendly_id_options[:use] << :globalize
33
+ friendly_id_options
34
+ end
35
+ end
20
36
 
21
- attr_accessible :id, :deletable, :link_url, :menu_match,
22
- :skip_to_first_child, :position, :show_in_menu, :draft,
23
- :parts_attributes, :parent_id, :menu_title, :page_id,
24
- :layout_template, :view_template, :custom_slug, :slug,
25
- :title, *::SeoMeta.attributes.keys
37
+ # If title changes tell friendly_id to regenerate slug when saving record
38
+ def should_generate_new_friendly_id?
39
+ changes.keys.include?("title") || changes.keys.include?("custom_slug")
40
+ end
41
+
42
+ # Delegate SEO Attributes to globalize translation
43
+ delegate(*(Translation.seo_fields << {:to => :translation}))
26
44
 
27
45
  validates :title, :presence => true
28
46
 
@@ -32,30 +50,19 @@ module Refinery
32
50
  # rather than :delete_all we want :destroy
33
51
  acts_as_nested_set :dependent => :destroy
34
52
 
35
- # Docs for friendly_id http://github.com/norman/friendly_id
36
- friendly_id_options = {:use => [:reserved, :globalize], :reserved_words => %w(index new session login logout users refinery admin images wymiframe)}
37
- if ::Refinery::Pages.scope_slug_by_parent
38
- friendly_id_options[:use] << :scoped
39
- friendly_id_options.merge!(:scope => :parent)
40
- end
41
-
42
- friendly_id :custom_slug_or_title, friendly_id_options
53
+ friendly_id :custom_slug_or_title, FriendlyIdOptions.options
43
54
 
44
- has_many :parts,
45
- :foreign_key => :refinery_page_id,
55
+ has_many :parts, -> {
56
+ scope = order('position ASC')
57
+ scope = scope.includes(:translations) if ::Refinery::PagePart.respond_to?(:translation_class)
58
+ scope
59
+ }, :foreign_key => :refinery_page_id,
46
60
  :class_name => '::Refinery::PagePart',
47
- :order => 'position ASC',
48
61
  :inverse_of => :page,
49
- :dependent => :destroy,
50
- :include => ((:translations) if ::Refinery::PagePart.respond_to?(:translation_class))
62
+ :dependent => :destroy
51
63
 
52
64
  accepts_nested_attributes_for :parts, :allow_destroy => true
53
65
 
54
- before_save do |m|
55
- m.translation.globalized_model = self
56
- m.translation.save if m.translation.new_record?
57
- end
58
- before_create :ensure_locale!
59
66
  before_destroy :deletable?
60
67
  after_save :reposition_parts!
61
68
 
@@ -68,36 +75,27 @@ module Refinery
68
75
 
69
76
  # Find page by path, checking for scoping rules
70
77
  def find_by_path(path)
71
- if ::Refinery::Pages.scope_slug_by_parent
72
- # With slugs scoped to the parent page we need to find a page by its full path.
73
- # For example with about/example we would need to find 'about' and then its child
74
- # called 'example' otherwise it may clash with another page called /example.
75
- path = path.split('/').select(&:present?)
76
- page = by_slug(path.shift, :parent_id => nil).first
77
- while page && path.any? do
78
- slug_or_id = path.shift
79
- page = page.children.by_slug(slug_or_id).first || page.children.find(slug_or_id)
80
- end
81
- else
82
- page = by_slug(path).first
83
- end
84
-
85
- page
78
+ Pages::Finder.by_path(path)
86
79
  end
87
80
 
88
81
  # Helps to resolve the situation where you have a path and an id
89
82
  # and if the path is unfriendly then a different finder method is required
90
83
  # than find_by_path.
91
84
  def find_by_path_or_id(path, id)
92
- if path.present?
93
- if path.friendly_id?
94
- find_by_path(path)
95
- else
96
- find(path)
97
- end
98
- elsif id.present?
99
- find(id)
100
- end
85
+ Pages::Finder.by_path_or_id(path, id)
86
+ end
87
+
88
+ # Helps to resolve the situation where you have a path and an id
89
+ # and if the path is unfriendly then a different finder method is required
90
+ # than find_by_path.
91
+ #
92
+ # raise ActiveRecord::RecordNotFound if not found.
93
+ def find_by_path_or_id!(path, id)
94
+ page = find_by_path_or_id(path, id)
95
+
96
+ raise ActiveRecord::RecordNotFound unless page
97
+
98
+ page
101
99
  end
102
100
 
103
101
  # Finds pages by their title. This method is necessary because pages
@@ -105,18 +103,15 @@ module Refinery
105
103
  # pages table thus requiring us to find the attribute on the translations table
106
104
  # and then join to the pages table again to return the associated record.
107
105
  def by_title(title)
108
- with_globalize(:title => title)
106
+ Pages::Finder.by_title(title)
109
107
  end
110
108
 
111
109
  # Finds pages by their slug. This method is necessary because pages
112
110
  # are translated which means the slug attribute does not exist on the
113
111
  # pages table thus requiring us to find the attribute on the translations table
114
112
  # and then join to the pages table again to return the associated record.
115
- def by_slug(slug, conditions={})
116
- with_globalize({
117
- :locale => Refinery::I18n.frontend_locales.map(&:to_s),
118
- :slug => slug
119
- }.merge(conditions))
113
+ def by_slug(slug, conditions = {})
114
+ Pages::Finder.by_slug(slug, conditions)
120
115
  end
121
116
 
122
117
  # Shows all pages with :show_in_menu set to true, but it also
@@ -134,19 +129,7 @@ module Refinery
134
129
 
135
130
  # Wrap up the logic of finding the pages based on the translations table.
136
131
  def with_globalize(conditions = {})
137
- conditions = {:locale => ::Globalize.locale.to_s}.merge(conditions)
138
- translations_conditions = {}
139
- translated_attrs = translated_attribute_names.map(&:to_s) | %w(locale)
140
-
141
- conditions.keys.each do |key|
142
- if translated_attrs.include? key.to_s
143
- translations_conditions["#{self.translation_class.table_name}.#{key}"] = conditions.delete(key)
144
- end
145
- end
146
-
147
- # A join implies readonly which we don't really want.
148
- where(conditions).joins(:translations).where(translations_conditions).
149
- readonly(false)
132
+ Pages::Finder.with_globalize(conditions)
150
133
  end
151
134
 
152
135
  # Returns how many pages per page should there be when paginating pages
@@ -161,6 +144,7 @@ module Refinery
161
144
  alias_method_chain :rebuild!, :slug_nullification
162
145
 
163
146
  protected
147
+
164
148
  def nullify_duplicate_slugs_under_the_same_parent!
165
149
  t_slug = translation_class.arel_table[:slug]
166
150
  joins(:translations).group(:locale, :parent_id, t_slug).having(t_slug.count.gt(1)).count.
@@ -174,7 +158,7 @@ module Refinery
174
158
  end
175
159
 
176
160
  def translated_to_default_locale?
177
- persisted? && translations.where(:locale => Refinery::I18n.default_frontend_locale).any?
161
+ persisted? && translations.any?{ |t| t.locale == Refinery::I18n.default_frontend_locale}
178
162
  end
179
163
 
180
164
  # The canonical page for this particular page.
@@ -193,7 +177,8 @@ module Refinery
193
177
  # Returns in cascading order: custom_slug or menu_title or title depending on
194
178
  # which attribute is first found to be present for this page.
195
179
  def custom_slug_or_title
196
- custom_slug.presence || menu_title.presence || title.presence
180
+ (Refinery::Pages.use_custom_slugs && custom_slug.presence) ||
181
+ menu_title.presence || title.presence
197
182
  end
198
183
 
199
184
  # Am I allowed to delete this page?
@@ -207,7 +192,7 @@ module Refinery
207
192
  # This ensures that they are in the correct 0,1,2,3,4... etc order.
208
193
  def reposition_parts!
209
194
  reload.parts.each_with_index do |part, index|
210
- part.update_attributes :position => index
195
+ part.update_columns position: index
211
196
  end
212
197
  end
213
198
 
@@ -223,56 +208,32 @@ module Refinery
223
208
 
224
209
  # If you want to destroy a page that is set to be not deletable this is the way to do it.
225
210
  def destroy!
226
- self.menu_match = nil
227
- self.link_url = nil
228
- self.deletable = true
211
+ self.update_attributes(:menu_match => nil, :link_url => nil, :deletable => true)
229
212
 
230
- destroy
213
+ self.destroy
231
214
  end
232
215
 
233
- # Used for the browser title to get the full path to this page
234
- # It automatically prints out this page title and all of it's parent page titles joined by a PATH_SEPARATOR
235
- def path(options = {})
236
- # Override default options with any supplied.
237
- options = {:reversed => true}.merge(options)
216
+ # Returns the full path to this page.
217
+ # This automatically prints out this page title and all parent page titles.
218
+ # The result is joined by the path_separator argument.
219
+ def path(path_separator: ' - ', ancestors_first: true)
220
+ return title if root?
238
221
 
239
- if parent_id
240
- parts = [title, parent.path(options)]
241
- parts.reverse! if options[:reversed]
242
- parts.join(' - ')
243
- else
244
- title
245
- end
222
+ chain = ancestors_first ? self_and_ancestors : self_and_ancestors.reverse
223
+ chain.map(&:title).join(path_separator)
246
224
  end
247
225
 
248
226
  def url
249
227
  Pages::Url.build(self)
250
228
  end
251
229
 
252
- def link_url_localised?
253
- Refinery.deprecate "Refinery::Page#link_url_localised?", :when => '2.2',
254
- :replacement => "Refinery::Pages::Url::Localised#url"
255
- Pages::Url::Localised.new(self).url
256
- end
257
-
258
- def url_normal
259
- Refinery.deprecate "Refinery::Page#url_normal", :when => '2.2',
260
- :replacement => "Refinery::Pages::Url::Normal#url"
261
- Pages::Url::Normal.new(self).url
262
- end
263
-
264
- def url_marketable
265
- Refinery.deprecate "Refinery::Page#url_marketable", :when => '2.2',
266
- :replacement => "Refinery::Pages::Url::Marketable#url"
267
- Pages::Url::Marketable.new(self).url
268
- end
269
-
270
230
  def nested_url
271
- globalized_slug = Globalize.with_locale(slug_locale) { to_param.to_s }
272
- if ::Refinery::Pages.scope_slug_by_parent
273
- [parent.try(:nested_url), globalized_slug].compact.flatten
274
- else
275
- [globalized_slug]
231
+ Globalize.with_locale(slug_locale) do
232
+ if ::Refinery::Pages.scope_slug_by_parent && !root?
233
+ self_and_ancestors.includes(:translations).map(&:to_param)
234
+ else
235
+ [to_param.to_s]
236
+ end
276
237
  end
277
238
  end
278
239
 
@@ -330,8 +291,8 @@ module Refinery
330
291
  # ::Refinery::Page.first.content_for(:body)
331
292
  #
332
293
  # Will return the body page part of the first page.
333
- def content_for(part_title)
334
- part_with_title(part_title).try(:body)
294
+ def content_for(part_slug)
295
+ part_with_slug(part_slug).try(:body)
335
296
  end
336
297
 
337
298
  # Accessor method to test whether a page part
@@ -341,34 +302,27 @@ module Refinery
341
302
  # ::Refinery::Page.first.content_for?(:body)
342
303
  #
343
304
  # Will return true if the page has a body page part and it is not blank.
344
- def content_for?(part_title)
345
- content_for(part_title).present?
305
+ def content_for?(part_slug)
306
+ content_for(part_slug).present?
346
307
  end
347
308
 
348
309
  # Accessor method to get a page part object from a page.
349
310
  # Example:
350
311
  #
351
- # ::Refinery::Page.first.part_with_title(:body)
312
+ # ::Refinery::Page.first.part_with_slug(:body)
352
313
  #
353
- # Will return the Refinery::PagePart object with that title using the first page.
354
- def part_with_title(part_title)
314
+ # Will return the Refinery::PagePart object with that slug using the first page.
315
+ def part_with_slug(part_slug)
355
316
  # self.parts is usually already eager loaded so we can now just grab
356
317
  # the first element matching the title we specified.
357
318
  self.parts.detect do |part|
358
- part.title.present? and # protecting against the problem that occurs when have nil title
359
- part.title == part_title.to_s or
360
- part.title.downcase.gsub(" ", "_") == part_title.to_s.downcase.gsub(" ", "_")
319
+ part.slug_matches?(part_slug)
361
320
  end
362
321
  end
363
322
 
364
- private
365
-
366
- # Make sures that a translation exists for this page.
367
- # The translation is set to the default frontend locale.
368
- def ensure_locale!
369
- if self.translations.empty?
370
- self.translations.build(:locale => Refinery::I18n.default_frontend_locale)
371
- end
323
+ def part_with_title(part_title)
324
+ Refinery.deprecate("Refinery::Page#part_with_title", when: "3.1", replacement: "part_with_slug")
325
+ part_with_slug(part_title.to_s.parameterize.underscore)
372
326
  end
373
327
 
374
328
  # Protects generated slugs from title if they are in the list of reserved words
@@ -377,21 +331,41 @@ module Refinery
377
331
  # Also check for global scoping, and if enabled, allow slashes in slug.
378
332
  #
379
333
  # Returns the sluggified string
380
- def normalize_friendly_id_with_marketable_urls(slug_string)
381
- # If we are scoping by parent, no slashes are allowed. Otherwise, slug is potentially
382
- # a custom slug that contains a custom route to the page.
383
- if !Pages.scope_slug_by_parent && slug_string.include?('/')
384
- slug_string.sub!(%r{^/*}, '').sub!(%r{/*$}, '') # Remove leading and trailing slashes, but allow internal
385
- slug_string.split('/').select(&:present?).map {|s| normalize_friendly_id_with_marketable_urls(s) }.join('/')
386
- else
334
+ def normalize_friendly_id(slug_string)
335
+ FriendlyIdPath.normalize_friendly_id(slug_string)
336
+ end
337
+
338
+ private
339
+
340
+ class FriendlyIdPath
341
+ def self.normalize_friendly_id_path(slug_string)
342
+ # Remove leading and trailing slashes, but allow internal
343
+ slug_string
344
+ .sub(%r{^/*}, '')
345
+ .sub(%r{/*$}, '')
346
+ .split('/')
347
+ .select(&:present?)
348
+ .map { |slug| self.normalize_friendly_id(slug) }.join('/')
349
+ end
350
+
351
+ def self.normalize_friendly_id(slug_string)
352
+ # If we are scoping by parent, no slashes are allowed. Otherwise, slug is
353
+ # potentially a custom slug that contains a custom route to the page.
354
+ if !Pages.scope_slug_by_parent && slug_string.include?('/')
355
+ self.normalize_friendly_id_path(slug_string)
356
+ else
357
+ self.protected_slug_string(slug_string)
358
+ end
359
+ end
360
+
361
+ def self.protected_slug_string(slug_string)
387
362
  sluggified = slug_string.to_slug.normalize!
388
- if Pages.marketable_urls && self.class.friendly_id_config.reserved_words.include?(sluggified)
363
+ if Pages.marketable_urls && Refinery::Pages.friendly_id_reserved_words.include?(sluggified)
389
364
  sluggified << "-page"
390
365
  end
391
366
  sluggified
392
367
  end
393
368
  end
394
- alias_method_chain :normalize_friendly_id, :marketable_urls
395
369
 
396
370
  def puts_destroy_help
397
371
  puts "This page is not deletable. Please use .destroy! if you really want it deleted "
@@ -401,9 +375,9 @@ module Refinery
401
375
  end
402
376
 
403
377
  def slug_locale
404
- return Globalize.locale if translation_for(Globalize.locale).try(:slug).present?
378
+ return Globalize.locale if translation_for(Globalize.locale, false).try(:slug).present?
405
379
 
406
- if translations.empty? || translation_for(Refinery::I18n.default_frontend_locale).present?
380
+ if translations.empty? || translation_for(Refinery::I18n.default_frontend_locale, false).present?
407
381
  Refinery::I18n.default_frontend_locale
408
382
  else
409
383
  translations.first.locale