nocms-pages 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +4 -0
- data/Rakefile +21 -0
- data/app/assets/stylesheets/pages/application.css +13 -0
- data/app/controllers/no_cms/pages/application_controller.rb +6 -0
- data/app/controllers/no_cms/pages/pages_controller.rb +12 -0
- data/app/helpers/no_cms/pages/application_helper.rb +6 -0
- data/app/models/no_cms/pages/block.rb +146 -0
- data/app/models/no_cms/pages/concerns/translation_scopes.rb +16 -0
- data/app/models/no_cms/pages/page.rb +37 -0
- data/app/views/layouts/nocms/pages/application.html.erb +14 -0
- data/app/views/no_cms/pages/blocks/_default.html.erb +8 -0
- data/app/views/no_cms/pages/pages/show.html.erb +6 -0
- data/config/locales/en.yml +18 -0
- data/config/routes.rb +6 -0
- data/db/migrate/20140226123742_create_no_cms_pages.rb +14 -0
- data/db/migrate/20140227100626_create_no_cms_blocks.rb +16 -0
- data/db/migrate/20140227143723_add_fields_info_to_no_cms_block.rb +5 -0
- data/db/migrate/20140228112643_add_slug_to_no_cms_page.rb +5 -0
- data/db/migrate/20140303092727_add_awesome_nested_set_to_no_cms_pages.rb +8 -0
- data/db/migrate/20140303100908_add_path_to_no_cms_page.rb +5 -0
- data/db/migrate/20140303123845_add_poisition_to_no_cms_block.rb +5 -0
- data/db/migrate/20140303145615_add_template_to_no_cms_page.rb +5 -0
- data/db/migrate/20140313171000_add_draft_to_block.rb +5 -0
- data/db/migrate/20140314110439_add_draft_to_pages.rb +5 -0
- data/lib/generators/nocms/pages_generator.rb +15 -0
- data/lib/generators/nocms/templates/config/initializers/nocms/pages.rb +25 -0
- data/lib/nocms/pages/configuration.rb +18 -0
- data/lib/nocms/pages/engine.rb +10 -0
- data/lib/nocms/pages/routes/page_found_constraint.rb +9 -0
- data/lib/nocms/pages/routes.rb +1 -0
- data/lib/nocms/pages/version.rb +5 -0
- data/lib/nocms_pages.rb +8 -0
- data/lib/tasks/pages_tasks.rake +4 -0
- metadata +153 -0
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Pages'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_dependency "no_cms/pages/application_controller"
|
2
|
+
|
3
|
+
module NoCms::Pages
|
4
|
+
class PagesController < ApplicationController
|
5
|
+
def show
|
6
|
+
@page = Page.no_drafts.where(path: "/#{params[:path]}").first
|
7
|
+
raise ActionController::RoutingError.new('Not Found') if @page.nil?
|
8
|
+
|
9
|
+
render @page.template unless @page.template.blank?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
module NoCms::Pages
|
2
|
+
class Block < ActiveRecord::Base
|
3
|
+
|
4
|
+
include Concerns::TranslationScopes
|
5
|
+
|
6
|
+
scope :drafts, ->() { where_with_locale(draft: true) }
|
7
|
+
scope :no_drafts, ->() { where_with_locale(draft: false) }
|
8
|
+
|
9
|
+
belongs_to :page
|
10
|
+
|
11
|
+
attr_reader :cached_objects
|
12
|
+
|
13
|
+
translates :layout, :fields_info, :draft
|
14
|
+
|
15
|
+
class Translation
|
16
|
+
serialize :fields_info, Hash
|
17
|
+
end
|
18
|
+
|
19
|
+
after_initialize :set_blank_fields
|
20
|
+
after_create :set_default_position
|
21
|
+
before_save :save_related_objects
|
22
|
+
|
23
|
+
validates :fields_info, presence: { allow_blank: true }
|
24
|
+
validates :page, :layout, presence: true
|
25
|
+
|
26
|
+
def layout_config
|
27
|
+
NoCms::Pages.block_layouts.stringify_keys[layout]
|
28
|
+
end
|
29
|
+
|
30
|
+
def template
|
31
|
+
layout_config[:template] if layout_config
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_field? field
|
35
|
+
# We have the field if...
|
36
|
+
!layout_config.nil? && # We have a layout configuration AND
|
37
|
+
(
|
38
|
+
!layout_config[:fields].symbolize_keys[field.to_sym].nil? || # We have this field OR
|
39
|
+
!layout_config[:fields].symbolize_keys[field.to_s.gsub(/\_id$/, '').to_sym].nil? # we remove the final _id and then we have the field
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def field_type field
|
44
|
+
return nil unless has_field?(field)
|
45
|
+
layout_config[:fields].symbolize_keys[field.to_sym]
|
46
|
+
end
|
47
|
+
|
48
|
+
def read_field field
|
49
|
+
return nil unless has_field?(field)
|
50
|
+
|
51
|
+
value = fields_info[field.to_sym] || # first, we get the value
|
52
|
+
@cached_objects[field.to_sym] # or we get it from the cached objects
|
53
|
+
|
54
|
+
# If value is still nil, but the field exists we must get the object from the database
|
55
|
+
if value.nil?
|
56
|
+
field_id = fields_info["#{field}_id".to_sym]
|
57
|
+
value = @cached_objects[field.to_sym] = field_type(field).find(field_id) unless field_id.nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
value
|
61
|
+
end
|
62
|
+
|
63
|
+
def write_field field, value
|
64
|
+
return nil unless has_field?(field)
|
65
|
+
field_type = field_type field
|
66
|
+
# If field type is a model then we update the cached object
|
67
|
+
if field_type.is_a?(Class) && field_type < ActiveRecord::Base
|
68
|
+
# First, we initialize the object if we don't read the object (it loads it into the cached objects)
|
69
|
+
@cached_objects[field.to_sym] = field_type.new if read_field(field).nil?
|
70
|
+
# Then, assign attributes
|
71
|
+
@cached_objects[field.to_sym].assign_attributes value
|
72
|
+
else # If it's a model then a new object or update the previous one
|
73
|
+
self.fields_info = fields_info.merge field.to_sym => value # when updating through an object (i.e. the page updates through nested attributes) fields_info[field.to_sym] = value doesn't work. Kudos to Rubo for this fix
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# In this missing method we check wether we're asking for one field
|
78
|
+
# in which case we will read or write ir
|
79
|
+
def method_missing(m, *args, &block)
|
80
|
+
# We get the name of the field stripping out the '=' for writers
|
81
|
+
field = m.to_s
|
82
|
+
write_accessor = field.ends_with? '='
|
83
|
+
field.gsub!(/\=$/, '')
|
84
|
+
|
85
|
+
# If this field actually exists, then we write it or read it.
|
86
|
+
if has_field?(field)
|
87
|
+
write_accessor ?
|
88
|
+
write_field(field, args.first) :
|
89
|
+
read_field(field.to_sym)
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# When we are assigning attributes (this method is called in new, create...)
|
96
|
+
# we must split those fields from our current layout and those who are not
|
97
|
+
# (they must be attributes).
|
98
|
+
# Attributes are processed the usual way and fields are written later
|
99
|
+
def assign_attributes new_attributes
|
100
|
+
fields = []
|
101
|
+
|
102
|
+
set_blank_fields
|
103
|
+
|
104
|
+
# We get the layout
|
105
|
+
new_layout = new_attributes[:layout] || new_attributes['layout']
|
106
|
+
self.layout = new_layout unless new_layout.nil?
|
107
|
+
|
108
|
+
# And now separate fields and attributes
|
109
|
+
fields = new_attributes.select{|k, _| has_field? k }.symbolize_keys
|
110
|
+
new_attributes.reject!{|k, _| has_field? k }
|
111
|
+
|
112
|
+
super(new_attributes)
|
113
|
+
|
114
|
+
Rails.logger.info "Writing #{fields.inspect} to #{self.layout} block"
|
115
|
+
|
116
|
+
fields.each do |field_name, value|
|
117
|
+
self.write_field field_name, value
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def reload
|
122
|
+
@cached_objects = {}
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def set_blank_fields
|
129
|
+
self.fields_info ||= {}
|
130
|
+
@cached_objects ||= {}
|
131
|
+
end
|
132
|
+
|
133
|
+
def set_default_position
|
134
|
+
self.update_attribute :position, ((page.blocks.pluck(:position).compact.max || 0) + 1) if self.position.blank?
|
135
|
+
end
|
136
|
+
|
137
|
+
def save_related_objects
|
138
|
+
cached_objects.each do |field, object|
|
139
|
+
if object.is_a?(ActiveRecord::Base) && object.changed?
|
140
|
+
object.save!
|
141
|
+
fields_info["#{field}_id".to_sym] = object.id
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module NoCms
|
2
|
+
module Pages
|
3
|
+
module Concerns
|
4
|
+
module TranslationScopes
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
scope :where_with_locale, ->(where_params, locale = ::I18n.locale) {
|
9
|
+
with_translations(locale).where(self::Translation.table_name => where_params)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module NoCms::Pages
|
2
|
+
class Page < ActiveRecord::Base
|
3
|
+
|
4
|
+
include Concerns::TranslationScopes
|
5
|
+
|
6
|
+
scope :drafts, ->() { where_with_locale(draft: true) }
|
7
|
+
scope :no_drafts, ->() { where_with_locale(draft: false) }
|
8
|
+
|
9
|
+
acts_as_nested_set
|
10
|
+
|
11
|
+
has_many :blocks, inverse_of: :page, class_name: 'NoCms::Pages::Block'
|
12
|
+
accepts_nested_attributes_for :blocks, allow_destroy: true
|
13
|
+
|
14
|
+
translates :title, :body, :slug, :path, :draft
|
15
|
+
|
16
|
+
validates :title, :body, presence: true
|
17
|
+
validates :slug, presence: { allow_blank: true }
|
18
|
+
|
19
|
+
before_validation :set_slug_and_path
|
20
|
+
after_move :rebuild_path
|
21
|
+
|
22
|
+
def set_slug_and_path
|
23
|
+
self.slug = title.parameterize if slug.nil? && !title.nil?
|
24
|
+
self.rebuild_path if path.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def rebuild_path
|
28
|
+
self.update_attribute :path, "#{ancestors.map(&:path).join}/#{slug}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.templates
|
32
|
+
Dir[Rails.root.join('app', 'views', 'no_cms', 'pages', 'pages', '*.html.erb').to_s]. # We get all page templates
|
33
|
+
map { |f| File.basename(f, '.html.erb') }.uniq.sort # And get their names
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Pages</title>
|
5
|
+
<%= stylesheet_link_tag "pages/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "pages/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
en:
|
2
|
+
activerecord:
|
3
|
+
models:
|
4
|
+
no_cms/pages/page: Page
|
5
|
+
no_cms/pages/block: Content Block
|
6
|
+
attributes:
|
7
|
+
no_cms/pages/page:
|
8
|
+
title: Title
|
9
|
+
body: Body
|
10
|
+
no_cms/pages/block:
|
11
|
+
layout: Layout
|
12
|
+
title: Title
|
13
|
+
body: Body
|
14
|
+
no_cms:
|
15
|
+
pages:
|
16
|
+
blocks:
|
17
|
+
layouts:
|
18
|
+
default: Default layout
|
data/config/routes.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateNoCmsPages < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :no_cms_pages_pages do |t|
|
4
|
+
t.timestamps
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table :no_cms_pages_page_translations do |t|
|
8
|
+
t.belongs_to :no_cms_pages_page, index: true
|
9
|
+
t.string :locale
|
10
|
+
t.string :title
|
11
|
+
t.string :body
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateNoCmsBlocks < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :no_cms_pages_blocks do |t|
|
4
|
+
t.belongs_to :page, index: true
|
5
|
+
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table :no_cms_pages_block_translations do |t|
|
10
|
+
t.belongs_to :no_cms_pages_block, index: true
|
11
|
+
t.string :locale
|
12
|
+
t.string :layout
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class AddAwesomeNestedSetToNoCmsPages < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
add_column :no_cms_pages_pages, :parent_id, :integer
|
4
|
+
add_column :no_cms_pages_pages, :lft, :integer
|
5
|
+
add_column :no_cms_pages_pages, :rgt, :integer
|
6
|
+
add_column :no_cms_pages_pages, :depth, :integer
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module NoCms
|
2
|
+
class PagesGenerator < Rails::Generators::Base
|
3
|
+
|
4
|
+
source_root File.expand_path("../templates/", __FILE__)
|
5
|
+
|
6
|
+
def generate_nocms_pages_initializer
|
7
|
+
template "config/initializers/nocms/pages.rb", File.join(destination_root, "config", "initializers", "nocms", "pages.rb")
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.namespace
|
11
|
+
"nocms:pages"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
NoCms::Pages.configure do |config|
|
2
|
+
|
3
|
+
# In this section we configure block layouts. It's just an array of layouts, each consisting on a hash.
|
4
|
+
# Each layout has a template and a list of fields with a type.
|
5
|
+
# E.g: config.block_layouts = {
|
6
|
+
# 'title-long_text' => {
|
7
|
+
# template: 'title-long_text',
|
8
|
+
# fields: {
|
9
|
+
# title: :string,
|
10
|
+
# long_text: :text
|
11
|
+
# }
|
12
|
+
# },
|
13
|
+
# 'title-3_columns_text' => {
|
14
|
+
# template: 'title-3_columns_text',
|
15
|
+
# fields: {
|
16
|
+
# title: :string,
|
17
|
+
# column_1: :text,
|
18
|
+
# column_2: :text,
|
19
|
+
# column_3: :text
|
20
|
+
# }
|
21
|
+
# }
|
22
|
+
# }
|
23
|
+
# config.block_layouts = {}
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module NoCms
|
2
|
+
module Pages
|
3
|
+
include ActiveSupport::Configurable
|
4
|
+
|
5
|
+
config_accessor :block_layouts
|
6
|
+
|
7
|
+
self.block_layouts = {
|
8
|
+
'default' => {
|
9
|
+
template: 'default',
|
10
|
+
fields: {
|
11
|
+
title: :string,
|
12
|
+
body: :text
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module NoCms::Pages::Routes
|
2
|
+
class PageFoundConstraint
|
3
|
+
|
4
|
+
# A filter URL must NOT have a qualification as the first of its path filters
|
5
|
+
def self.matches?(request)
|
6
|
+
@page = NoCms::Pages::Page.no_drafts.where(path: "/#{request.params[:path]}").exists?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'nocms/pages/routes/page_found_constraint'
|
data/lib/nocms_pages.rb
ADDED