nocms-pages 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +4 -0
  4. data/Rakefile +21 -0
  5. data/app/assets/stylesheets/pages/application.css +13 -0
  6. data/app/controllers/no_cms/pages/application_controller.rb +6 -0
  7. data/app/controllers/no_cms/pages/pages_controller.rb +12 -0
  8. data/app/helpers/no_cms/pages/application_helper.rb +6 -0
  9. data/app/models/no_cms/pages/block.rb +146 -0
  10. data/app/models/no_cms/pages/concerns/translation_scopes.rb +16 -0
  11. data/app/models/no_cms/pages/page.rb +37 -0
  12. data/app/views/layouts/nocms/pages/application.html.erb +14 -0
  13. data/app/views/no_cms/pages/blocks/_default.html.erb +8 -0
  14. data/app/views/no_cms/pages/pages/show.html.erb +6 -0
  15. data/config/locales/en.yml +18 -0
  16. data/config/routes.rb +6 -0
  17. data/db/migrate/20140226123742_create_no_cms_pages.rb +14 -0
  18. data/db/migrate/20140227100626_create_no_cms_blocks.rb +16 -0
  19. data/db/migrate/20140227143723_add_fields_info_to_no_cms_block.rb +5 -0
  20. data/db/migrate/20140228112643_add_slug_to_no_cms_page.rb +5 -0
  21. data/db/migrate/20140303092727_add_awesome_nested_set_to_no_cms_pages.rb +8 -0
  22. data/db/migrate/20140303100908_add_path_to_no_cms_page.rb +5 -0
  23. data/db/migrate/20140303123845_add_poisition_to_no_cms_block.rb +5 -0
  24. data/db/migrate/20140303145615_add_template_to_no_cms_page.rb +5 -0
  25. data/db/migrate/20140313171000_add_draft_to_block.rb +5 -0
  26. data/db/migrate/20140314110439_add_draft_to_pages.rb +5 -0
  27. data/lib/generators/nocms/pages_generator.rb +15 -0
  28. data/lib/generators/nocms/templates/config/initializers/nocms/pages.rb +25 -0
  29. data/lib/nocms/pages/configuration.rb +18 -0
  30. data/lib/nocms/pages/engine.rb +10 -0
  31. data/lib/nocms/pages/routes/page_found_constraint.rb +9 -0
  32. data/lib/nocms/pages/routes.rb +1 -0
  33. data/lib/nocms/pages/version.rb +5 -0
  34. data/lib/nocms_pages.rb +8 -0
  35. data/lib/tasks/pages_tasks.rake +4 -0
  36. metadata +153 -0
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ nocms-pages
2
+ ===========
3
+
4
+ Gem with content page functionality independent from any CMS embeddable in any Rails 4 app
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,6 @@
1
+ module NoCms
2
+ module Pages
3
+ class ApplicationController < ActionController::Base
4
+ end
5
+ end
6
+ end
@@ -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,6 @@
1
+ module NoCms
2
+ module Pages
3
+ module ApplicationHelper
4
+ end
5
+ end
6
+ 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,8 @@
1
+ <div class='block'>
2
+ <% block.fields_info.each do |field_name, field_content| %>
3
+ <div class="<%=field_name %>">
4
+ <h2><%=field_name %></h2>
5
+ <p><%= field_content %></p>
6
+ </div>
7
+ <% end %>
8
+ </div>
@@ -0,0 +1,6 @@
1
+ <h1><%= @page.title %></h1>
2
+ <p><%= @page.body %></p>
3
+
4
+ <% @page.blocks.no_drafts.each do |block| %>
5
+ <%= render "no_cms/pages/blocks/#{block.template}", block: block %>
6
+ <% end %>
@@ -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,6 @@
1
+ NoCms::Pages::Engine.routes.draw do
2
+
3
+ get '*path', to: 'pages#show', constraints: NoCms::Pages::Routes::PageFoundConstraint
4
+ root to: 'pages#show', path:''
5
+
6
+ end
@@ -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,5 @@
1
+ class AddFieldsInfoToNoCmsBlock < ActiveRecord::Migration
2
+ def change
3
+ add_column :no_cms_pages_block_translations, :fields_info, :longtext, default: Hash.new.to_yaml
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddSlugToNoCmsPage < ActiveRecord::Migration
2
+ def change
3
+ add_column :no_cms_pages_page_translations, :slug, :string
4
+ end
5
+ 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,5 @@
1
+ class AddPathToNoCmsPage < ActiveRecord::Migration
2
+ def change
3
+ add_column :no_cms_pages_page_translations, :path, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddPoisitionToNoCmsBlock < ActiveRecord::Migration
2
+ def change
3
+ add_column :no_cms_pages_blocks, :position, :integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddTemplateToNoCmsPage < ActiveRecord::Migration
2
+ def change
3
+ add_column :no_cms_pages_pages, :template, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddDraftToBlock < ActiveRecord::Migration
2
+ def change
3
+ add_column :no_cms_pages_block_translations, :draft, :boolean, default: false
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddDraftToPages < ActiveRecord::Migration
2
+ def change
3
+ add_column :no_cms_pages_page_translations, :draft, :boolean, default: false
4
+ end
5
+ 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,10 @@
1
+ require 'globalize'
2
+ require 'awesome_nested_set'
3
+
4
+ module NoCms
5
+ module Pages
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace NoCms::Pages
8
+ end
9
+ end
10
+ 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'
@@ -0,0 +1,5 @@
1
+ module NoCms
2
+ module Pages
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require "nocms/pages/engine"
2
+ require 'nocms/pages/configuration'
3
+ require "nocms/pages/routes"
4
+
5
+ module NoCms
6
+ module Pages
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :pages do
3
+ # # Task goes here
4
+ # end