Skip to content

Commit 35b7527

Browse files
committed
Convert PageLayout into ActiveModel
Hashes are weak key value stores, while this warrants a concrete model with a strong contract.
1 parent 17ca3e5 commit 35b7527

20 files changed

Lines changed: 154 additions & 212 deletions

File tree

app/controllers/alchemy/admin/elements_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def create
3535
else
3636
Element.new(create_element_params)
3737
end
38-
if @page.definition["insert_elements_at"] == "top"
38+
if @page.definition.insert_elements_at == "top"
3939
@insert_at_top = true
4040
@element.position = 1
4141
end

app/models/alchemy/page.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ def all_from_clipboard_for_select(clipboard, language_id, layoutpages: false)
238238

239239
clipboard_pages = all_from_clipboard(clipboard)
240240
allowed_page_layouts = Alchemy::Page.selectable_layouts(language_id, layoutpages: layoutpages)
241-
allowed_page_layout_names = allowed_page_layouts.collect { |p| p["name"] }
241+
allowed_page_layout_names = allowed_page_layouts.collect(&:name)
242242
clipboard_pages.select { |cp| allowed_page_layout_names.include?(cp.page_layout) }
243243
end
244244

app/models/alchemy/page/fixed_attributes.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def initialize(page)
3131
# @return Hash
3232
#
3333
def attributes
34-
@_attributes ||= page.definition.fetch("fixed_attributes", {}).symbolize_keys
34+
@_attributes ||= page.definition.fixed_attributes.symbolize_keys
3535
end
3636
alias_method :all, :attributes
3737

app/models/alchemy/page/page_elements.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ def duplicate_elements(elements, repository, page_version)
8181
#
8282
def available_element_definitions(only_element_named = nil)
8383
@_available_element_definitions ||= if only_element_named
84-
definition = Element.definition_by_name(only_element_named)
85-
element_definitions_by_name(definition["nestable_elements"])
84+
element_definition = Element.definition_by_name(only_element_named)
85+
element_definitions_by_name(element_definition["nestable_elements"])
8686
else
8787
element_definitions.dup
8888
end
@@ -132,7 +132,7 @@ def descendent_element_definitions
132132
definitions.select { |d| d.key?("nestable_elements") }.each do |d|
133133
definitions += element_definitions_by_name(d["nestable_elements"])
134134
end
135-
definitions.uniq { |d| d["name"] }
135+
definitions.uniq { _1["name"] }
136136
end
137137

138138
# All names of elements that are defined in the page definition.
@@ -145,7 +145,7 @@ def descendent_element_definitions
145145
# elements: [headline, contactform]
146146
#
147147
def element_definition_names
148-
definition["elements"] || []
148+
definition.elements || []
149149
end
150150

151151
# Element definitions with given name(s)
@@ -181,7 +181,7 @@ def richtext_ingredients_ids
181181
# And if so, it generates them.
182182
#
183183
def generate_elements
184-
definition.fetch("autogenerate", []).each do |element_name|
184+
definition.autogenerate&.each do |element_name|
185185
Element.create(page: self, page_version: draft_version, name: element_name)
186186
end
187187
end

app/models/alchemy/page/page_layouts.rb

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ def layouts_repository=(klass)
1919
# Returns page layouts ready for Rails' select form helper.
2020
#
2121
def layouts_for_select(language_id, layoutpages: false)
22-
@map_array = []
23-
mapped_layouts_for_select(selectable_layouts(language_id, layoutpages: layoutpages))
22+
layouts = selectable_layouts(language_id, layoutpages: layoutpages)
23+
layouts.map do |layout|
24+
[layout.human_name, layout.name]
25+
end
2426
end
2527

2628
# Returns all layouts that can be used for creating a new page.
@@ -36,9 +38,9 @@ def selectable_layouts(language_id, layoutpages: false)
3638
@language_id = language_id
3739
layouts_repository.all.select do |layout|
3840
if layoutpages
39-
layout["layoutpage"] && layout_available?(layout)
41+
layout.layoutpage && layout_available?(layout)
4042
else
41-
!layout["layoutpage"] && layout_available?(layout)
43+
!layout.layoutpage && layout_available?(layout)
4244
end
4345
end
4446
end
@@ -65,25 +67,16 @@ def layouts_repository
6567
@_layouts_repository ||= PageLayout
6668
end
6769

68-
# Maps given layouts for Rails select form helper.
69-
#
70-
def mapped_layouts_for_select(layouts)
71-
layouts.each do |layout|
72-
@map_array << [human_layout_name(layout["name"]), layout["name"]]
73-
end
74-
@map_array
75-
end
76-
7770
# Returns true if the given layout is unique and not already taken or it should be hidden.
7871
#
7972
def layout_available?(layout)
80-
!layout["hide"] && !already_taken?(layout) && available_on_site?(layout)
73+
!layout.hide && !already_taken?(layout) && available_on_site?(layout)
8174
end
8275

8376
# Returns true if this layout is unique and already taken by another page.
8477
#
8578
def already_taken?(layout)
86-
layout["unique"] && page_with_layout_existing?(layout["name"])
79+
layout.unique && page_with_layout_existing?(layout.name)
8780
end
8881

8982
# Returns true if one page already has the given layout
@@ -106,7 +99,7 @@ def available_on_site?(layout)
10699
return false unless Alchemy::Current.site
107100

108101
Alchemy::Current.site.definition.blank? ||
109-
Alchemy::Current.site.definition.fetch("page_layouts", []).include?(layout["name"])
102+
Alchemy::Current.site.definition.fetch("page_layouts", []).include?(layout.name)
110103
end
111104
end
112105
end

app/models/alchemy/page/page_natures.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ def folded?(user_id)
3838
# @returns Array
3939
#
4040
def has_limited_editors?
41-
definition["editable_by"].present?
41+
definition.editable_by.present?
4242
end
4343

4444
def editor_roles
4545
return unless has_limited_editors?
4646

47-
definition["editable_by"]
47+
definition.editable_by
4848
end
4949

5050
# True if page locked_at timestamp and locked_by id are set
@@ -83,7 +83,7 @@ def definition
8383
definition = PageLayout.get(page_layout)
8484
if definition.nil?
8585
log_warning "Page definition for `#{page_layout}` not found. Please check `page_layouts.yml` file."
86-
return {}
86+
return PageLayout.new(name: page_layout)
8787
end
8888
definition
8989
end
@@ -147,7 +147,7 @@ def cache_page?
147147
return false unless caching_enabled?
148148

149149
page_layout = PageLayout.get(self.page_layout)
150-
page_layout["cache"] != false && page_layout["searchresults"] != true
150+
page_layout.cache != false && page_layout.searchresults != true
151151
end
152152

153153
private
Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,46 @@
22

33
module Alchemy
44
class PageLayout
5+
include ActiveModel::Model
6+
include ActiveModel::Attributes
7+
8+
extend ActiveModel::Translation
9+
10+
attribute :name, :string
11+
attribute :elements, default: []
12+
attribute :autogenerate, default: []
13+
attribute :layoutpage, :boolean, default: false
14+
attribute :unique, :boolean, default: false
15+
attribute :cache, :boolean, default: true
16+
attribute :insert_elements_at, :string, default: "bottom"
17+
attribute :fixed_attributes, default: {}
18+
attribute :searchable, :boolean, default: true
19+
attribute :searchresults, :boolean, default: false
20+
attribute :hide, :boolean, default: false
21+
attribute :editable_by
22+
attribute :hint
23+
24+
validates :name,
25+
presence: true,
26+
format: {
27+
with: /\A[a-z_-]+\z/
28+
}
29+
30+
delegate :[], to: :attributes
31+
532
class << self
633
# Returns all page layouts.
734
#
835
# They are defined in +config/alchemy/page_layout.yml+ file.
936
#
1037
def all
11-
@definitions ||= read_definitions_file.map(&:with_indifferent_access)
38+
@definitions ||= read_definitions_file.map { new(**_1) }
39+
end
40+
41+
def map(...)
42+
all.map(...)
1243
end
44+
alias_method :collect, :map
1345

1446
# Add additional page definitions to collection.
1547
#
@@ -22,23 +54,17 @@ def all
2254
# @param [Array || Hash]
2355
# You can pass a single layout definition as Hash, or a collection of page layouts as Array.
2456
#
25-
def add(page_layout)
57+
def add(definition)
2658
all
27-
if page_layout.is_a?(Array)
28-
@definitions += page_layout
29-
elsif page_layout.is_a?(Hash)
30-
@definitions << page_layout
31-
else
32-
raise TypeError
33-
end
59+
@definitions += Array.wrap(definition).map { new(**_1) }
3460
end
3561

3662
# Returns one page definition by given name.
3763
#
3864
def get(name)
39-
return {} if name.blank?
65+
return new if name.blank?
4066

41-
all.detect { |a| a["name"].casecmp(name).zero? }
67+
all.detect { _1.name.casecmp(name).zero? }
4268
end
4369

4470
def reset!
@@ -69,5 +95,13 @@ def read_definitions_file
6995
end
7096
end
7197
end
98+
99+
def human_name
100+
Alchemy::Page.human_layout_name(name)
101+
end
102+
103+
def attributes
104+
super.with_indifferent_access
105+
end
72106
end
73107
end

app/models/alchemy/site/layout.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ def definition
4141
#
4242
def page_layout_names(layoutpages: false)
4343
page_layout_definitions.select do |layout|
44-
!!layout["layoutpage"] && layoutpages || !layout["layoutpage"] && !layoutpages
45-
end.collect { |layout| layout["name"] }
44+
!!layout.layoutpage && layoutpages || !layout.layoutpage && !layoutpages
45+
end.tap { _1.collect!(&:name) }
4646
end
4747

4848
# Returns sites page layout definitions
@@ -52,7 +52,7 @@ def page_layout_names(layoutpages: false)
5252
def page_layout_definitions
5353
if definition["page_layouts"].presence
5454
Alchemy::PageLayout.all.select do |layout|
55-
layout["name"].in?(definition["page_layouts"])
55+
layout.name.in?(definition["page_layouts"])
5656
end
5757
else
5858
Alchemy::PageLayout.all

lib/alchemy/engine.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,18 @@ class Engine < Rails::Engine
6262
end
6363
end
6464

65-
initializer "alchemy.watch_definition_changes" do |app|
66-
elements_reloader = app.config.file_watcher.new([ElementDefinition.definitions_file_path]) do
65+
config.to_prepare do
66+
elements_reloader = Rails.application.config.file_watcher.new([ElementDefinition.definitions_file_path]) do
6767
Rails.logger.info "[#{engine_name}] Reloading Element Definitions."
6868
ElementDefinition.reset!
6969
end
70-
page_layouts_reloader = app.config.file_watcher.new([PageLayout.layouts_file_path]) do
70+
page_layouts_reloader = Rails.application.config.file_watcher.new([PageLayout.layouts_file_path]) do
7171
Rails.logger.info "[#{engine_name}] Reloading Page Layouts."
7272
PageLayout.reset!
7373
end
7474
[elements_reloader, page_layouts_reloader].each do |reloader|
75-
app.reloaders << reloader
76-
app.reloader.to_run do
75+
Rails.application.reloaders << reloader
76+
Rails.application.reloader.to_run do
7777
reloader.execute_if_updated
7878
end
7979
end

lib/alchemy/tasks/usage.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def elements_count_by_name
1111
.group(:name)
1212
.order("count DESC, name ASC")
1313
.map { |e| {"name" => e.name, "count" => e.count} }
14-
Alchemy::Element.definitions.reject { |definition| res.map { |e| e["name"] }.include? definition["name"] }.sort_by { |d| d["name"] }.each do |definition|
14+
Alchemy::Element.definitions.reject { |definition| res.map { |e| e["name"] }.include?(definition["name"]) }.sort_by { _1["name"] }.each do |definition|
1515
res << {"name" => definition["name"], "count" => 0}
1616
end
1717
res
@@ -23,8 +23,8 @@ def pages_count_by_type
2323
.group(:page_layout)
2424
.order("count DESC, page_layout ASC")
2525
.map { |p| {"page_layout" => p.page_layout, "count" => p.count} }
26-
Alchemy::PageLayout.all.reject { |page_layout| res.map { |p| p["page_layout"] }.include? page_layout["name"] }.sort_by { |d| d["name"] }.each do |page_layout|
27-
res << {"page_layout" => page_layout["name"], "count" => 0}
26+
Alchemy::PageLayout.all.reject { |page_layout| res.map { |p| p["page_layout"] }.include?(page_layout.name) }.sort_by(&:name).each do |page_layout|
27+
res << {"page_layout" => page_layout.name, "count" => 0}
2828
end
2929
res
3030
end

0 commit comments

Comments
 (0)