diff --git a/README.md b/README.md index af80ce2..e1e2e64 100644 --- a/README.md +++ b/README.md @@ -29,12 +29,50 @@ on line 122 of the Active Admin initializer. Now you shall run the migration and seeds with: ```ruby -bundle exec rake db:setup +bundle exec rake db:create +bundle exec rake db:migrate ``` To verify, start the server and visit `localhost:3000/admin`. If you can login as `admin@example.com` with the password `password` you have successfully completed this step. +### Atomic CMS +#### Routes +Update your `config/routes.rb` to include the following: +```ruby +mount AtomicCms::Engine => "/atomic_cms", as: :atomic_cms +# If you are going to use a catch all route add the following line +get "*path", to: "pages#show", controller: "pages", as: :page, format: false +root to: 'pages#show', controller: "pages" +``` +The last two lines need to be at the **END** of your `routes.rb` file. + +##### Devise Authentication +Change the mount point above to be the following: +```ruby + authenticate :admin_user, -> (u) { u.admin? } do + mount AtomicCms::Engine => "/atomic_cms", as: :atomic_cms + end +``` +where `u` is the user and `admin?` the authentication method you have on that +user; it should return a boolean value. + +#### Scaffold Generator +Execute the following to create a model for your static pages: +```ruby +rails g atomic_cms:scaffold page +``` +*After this you should run your migrations.* + +Here is a list of everything that is generated for you: + +* Model +* Controller +* Active Admin Form +* Migration **Will need to be edited** +* Show View +* Route + ### Media Upload To install the media tables so that you can upload files until your heart is literally full run: @@ -104,234 +142,29 @@ this is properly imported: // // .status_tag { background: #6090DB; } ``` +*NOTE:* At the minimum, here is what is needed in `active_admin.scss`: +```scss +@import "active_admin/mixins"; +@import "active_admin/base"; +@import "atomic_cms"; -### Atomic CMS -#### Routes -Update your `config/routes.rb` to include the following: -```ruby -mount AtomicCms::Engine => "/atomic_cms", as: :atomic_cms -get "*path", to: "pages#show", controller: "pages", as: :page, format: false -root to: 'pages#show', controller: "pages" -``` -The last two lines need to be at the **END** of your `routes.rb` file. - -##### Devise Authentication -Change the mount point above to be the following: -```ruby - authenticate :admin_user, -> (u) { u.admin? } do - mount AtomicCms::Engine => "/atomic_cms", as: :atomic_cms - end -``` -where `u` is the user and `admin?` the authentication method you have on that -user; it should return a boolean value. - -#### Model -Execute the following to create a model for your static pages: -```ruby -rails g model pages title:string path:string content:text -``` -After this you should run your migrations. - -Update your Page model to match the following: -```ruby -class Page < ActiveRecord::Base - include AtomicCms::HasComponents - validates :title, :path, presence: true, uniqueness: true - component_attr :content -end -``` -#### Controller -Create a controller by running the following: -```ruby -rails g controller pages +#component_preview { + // Include application specific styling here +} ``` -Update your PagesController to match the following: -```ruby -require 'json' - -class PagesController < ApplicationController - def show - @page = Page.find_by_path(request.path) - if @page - render cms_template - else - render file: "#{Rails.root}/public/404.html", status: :not_found - Rails.logger.error "404 - Page #{request.path} cannot be found." - end - end - - private - def cms_template - File.join("pages", "page") - end -end -``` -#### Views -Create a view at `app/views/pages/page.html.slim` that contains the following: -```ruby -= @page.content_object.render -``` #### Components -Create the following component view at -`app/views/components/text_block.html.slim`: -```slim -.wrapper.large-margin - .text-block - .content-text - - if add_option(options[:header]) - h2 - = options[:header] - = markdown(options[:content]) +Generate components by executing the following: ``` -Create the following component class at `app/components/text_block_component.rb`: -```ruby -class TextBlockComponent < AtomicAssets::Component - def edit - rtn = cms_fields(field_types) - rtn << h.component(:text_block, field_previews).render - rtn.html_safe - end - - protected - - def field_previews - { - header: "{{preview.header}}", - content: markdown_preview('preview.content') - } - end - - def field_types - { - header: { field_type: "text" }, - content: { field_type: "markdown" } - } - end -end +rails g atomic_assets:component text_block ``` -Add the following to `app/assets/stylesheets/components/_text_block.scss`: -```scss -.text-block{ - position: relative; - .content-text{ - ul{ - margin-left: 10px; - padding-left: 0px; - position: relative; - display: inline-block; - li{ - list-style: disc; - margin-left: 20px; - } - } - } - &:before { - content: ''; - display: inline-block; - height: 100%; - vertical-align: middle; - margin-right: -0.25em; /* Adjusts for spacing */ - } -} -``` -### More Active Admin -In order to add components to a page, create -`app/views/admin/_edit_buttons.html.slim` and make it match the following: +In order for components to be utilized when managing content, a partial needs to +be created similar to the following at `app/views/admin/_edit_buttons.html.slim`: ```slim ol.edit-buttons li = link_to 'Text Block', atomic_cms.edit_component_path('text_block'), class: 'button' ``` -Create an admin page for the Pages model at `app/admin/page.rb` and make it -match the following: -```ruby -ActiveAdmin.register Page do - permit_params :title, :path, :content - - index do - selectable_column - column :path - column :title - column :created_at - column :updated_at - actions - end - - form html: { class: "edit-atomic-content" } do |f| - f.semantic_errors(*f.object.errors.keys) - - # new form - if !f.object.persisted? - f.inputs "Page Details" do - f.input :title - f.input :path - end - f.actions - - # edit form - else - div class: "buttons" do - render partial: "admin/edit_buttons" - f.actions - end - - columns do - column span: 3 do - panel "Draft", id: "draft-panel" do - render partial: "components/edit", locals: { f: f } - end - end - - column id: "edit-node-column" do - div id: "edit-page" do - f.inputs "Page Details" do - f.input :cms_type, type: :hidden, - input_html: { value: "page", id: "cms_type" } - f.input :title - f.input :path - end - end - - div id: "edit-node" do - f.inputs "Edit Element" do - div id: "edit-node-fields" - end - - f.actions do - li class: "move" do - a "Up", "#", class: "button", id: "move-node-up" - end - li class: "move" do - a "Down", "#", class: "button", id: "move-node-down" - end - li class: "cancel" do - a "Done", "#", class: "button", id: "done-edit-node" - end - li class: "delete" do - a "Delete", "#", class: "button", id: "delete-node" - end - end - end - end - end - end - end - - show do - div id: "component_preview" do - div page.content_render - end - end - - controller do - # permit all params until we can whitelist content_object - def permitted_params - params.permit! - end - end -end -``` #### Config Update `config/application.rb` to include: ```ruby diff --git a/atomic_cms.gemspec b/atomic_cms.gemspec index c47598a..572ec7d 100644 --- a/atomic_cms.gemspec +++ b/atomic_cms.gemspec @@ -1,19 +1,18 @@ Gem::Specification.new do |s| s.name = 'atomic_cms' - s.version = '0.2.1' + s.version = '0.2.2' s.date = '2015-06-19' s.summary = 'Atomic CMS' s.description = 'Live CMS powered by atomic assets.' s.authors = ['Don Humphreys'] s.email = 'dhumphreys88@gmail.com' - s.files = `git ls-files lib`.split(/\n/) + s.files = `git ls-files`.split(/\n/) s.test_files = Dir['spec/**/*'] # s.homepage = 'http://rubygems.org/gems/atomic_cms' # s.license = 'MIT' s.add_dependency 'rails', '~> 4.2' s.add_dependency 'activeadmin', '1.0.0.pre2' - s.add_dependency 'angularjs-rails', '~> 1.3', '< 1.4' s.add_dependency 'atomic_assets', '~> 0.1.0' s.add_dependency 'jquery-rails', '~> 4.0', '>= 4.0.3' s.add_dependency 'redcarpet', '~> 3.3' diff --git a/lib/generators/atomic_cms/assets/assets_generator.rb b/lib/generators/atomic_cms/assets/assets_generator.rb index 9bf9083..a9008d1 100644 --- a/lib/generators/atomic_cms/assets/assets_generator.rb +++ b/lib/generators/atomic_cms/assets/assets_generator.rb @@ -1,22 +1,48 @@ module AtomicCms module Generators class AssetsGenerator < Rails::Generators::Base + def install_bourbon + gem "bourbon", "~> 4.2.6" + end + + def install_neat + gem "neat", "~> 1.7.2" + end + + def install_bitters + gem "bitters", "~> 1.1.0" + run "bitters install --path ./app/assets/stylesheets" + end + + def install_angular + gem "angularjs-rails", "~> 1.3", "< 1.4" + end + def initialize_active_admin_javascript - javascript_asset = 'app/assets/javascripts/active_admin.js.coffee' + javascript_asset = "app/assets/javascripts/active_admin.js.coffee" entries = [ - '#= require angular', - '#= require angular-sanitize', - '#= require atomic_cms' + "#= require angular", + "#= require angular-sanitize", + "#= require atomic_cms" ] append_to_file( asset_file: javascript_asset, entries: entries ) end def initialize_active_admin_scss - scss_asset = 'app/assets/stylesheets/active_admin.scss' + scss_asset = "app/assets/stylesheets/active_admin.scss" entries = [ - '@import "atomic_cms"', + '@import "bourbon";', + '@import "neat";', + '@import "base/variables";', + '@import "base/grid-settings";', + '@import "atomic_cms";', '', '#component_preview {', + ' @import "base/buttons";', + ' @import "base/forms";', + ' @import "base/lists";', + ' @import "base/tables";', + ' @import "base/typography";', ' // When editing a page through Atomic CMS', ' // images with broken links should not be displayed.', ' img[src="image"] { display:none !important; }', @@ -28,7 +54,7 @@ def initialize_active_admin_scss private def append_to_file(options) - open(options[:asset_file], 'a') do |asset_file| + open(options[:asset_file], "a") do |asset_file| options[:entries].each do |entry| asset_file.puts entry end diff --git a/lib/generators/atomic_cms/scaffold/scaffold_generator.rb b/lib/generators/atomic_cms/scaffold/scaffold_generator.rb new file mode 100644 index 0000000..41bcf36 --- /dev/null +++ b/lib/generators/atomic_cms/scaffold/scaffold_generator.rb @@ -0,0 +1,76 @@ +require "active_support/core_ext/string" + +module AtomicCms + module Generators + class ScaffoldGenerator < Rails::Generators::Base + argument :model_name, required: true + + desc <<-DESC.strip_heredoc + Create a model, controller, view, admin resource, and route. + DESC + + source_root File.expand_path("../../templates", __FILE__) + + def install_model_template + setup_scaffold + create_template( + template_name: "model.erb", + full_path: "app/models/#{@scaffold.model_file_name}.rb" + ) + end + + def install_controller_template + create_template( + template_name: "controller.erb", + full_path: controller_template_name + ) + end + + def install_admin_template + create_template( + template_name: "admin.erb", + full_path: "app/admin/#{@scaffold.model_file_name}.rb" + ) + end + + def install_show_view_template + create_template( + template_name: "show.html.slim", + full_path: "app/views/#{@scaffold.view_folder}/show.html.slim" + ) + end + + def create_migration + generate "migration", "create#{@scaffold.model_name} name:string content:text" + end + + def set_route + inject_into_file( + "config/routes.rb", + "\n resources :#{@scaffold.controller_file_name}\n", + after: %r{/atomic_cms"} + ) + end + + private + + def setup_scaffold + @scaffold = OpenStruct.new( + model_name: model_name.singularize.titlecase, + model_file_name: model_name.singularize.downcase.underscore, + controller_name: model_name.pluralize.titlecase, + controller_file_name: model_name.pluralize.downcase, + view_folder: model_name.singularize.downcase.underscore + ) + end + + def create_template(options) + template(options[:template_name], options[:full_path]) + end + + def controller_template_name + "app/controllers/#{@scaffold.controller_file_name}_controller.rb" + end + end + end +end diff --git a/lib/generators/atomic_cms/templates/admin.erb b/lib/generators/atomic_cms/templates/admin.erb new file mode 100644 index 0000000..d48d080 --- /dev/null +++ b/lib/generators/atomic_cms/templates/admin.erb @@ -0,0 +1,79 @@ +ActiveAdmin.register <%= @scaffold.model_name %> do + permit_params :content + + index do + selectable_column + column :created_at + column :updated_at + actions + end + + form html: { class: "edit-atomic-content" } do |f| + f.semantic_errors(*f.object.errors.keys) + + # new form + if !f.object.persisted? + f.inputs "Details" do + # f.input :name + end + f.actions + + # edit form + else + div class: "buttons" do + render partial: "admin/edit_buttons" + f.actions + end + + columns do + column span: 3 do + panel "Draft", id: "draft-panel" do + render partial: "components/edit", locals: { f: f } + end + end + + column id: "edit-node-column" do + div id: "edit-<%= @scaffold.model_file_name %>" do + f.inputs "<%= @scaffold.model_name %> Details" do + # f.input :name + end + end + + div id: "edit-node" do + f.inputs "Edit Element" do + div id: "edit-node-fields" + end + + f.actions do + li class: "move" do + a "Up", "#", class: "button", id: "move-node-up" + end + li class: "move" do + a "Down", "#", class: "button", id: "move-node-down" + end + li class: "cancel" do + a "Done", "#", class: "button", id: "done-edit-node" + end + li class: "delete" do + a "Delete", "#", class: "button", id: "delete-node" + end + end + end + end + end + end + end + + show do + div id: "component_preview" do + div page.content_render + end + end + + controller do + # permit all params until we can whitelist content_object + def permitted_params + params.permit! + end + end +end diff --git a/lib/generators/atomic_cms/templates/controller.erb b/lib/generators/atomic_cms/templates/controller.erb new file mode 100644 index 0000000..c40fb95 --- /dev/null +++ b/lib/generators/atomic_cms/templates/controller.erb @@ -0,0 +1,16 @@ +require 'json' + +class <%= @scaffold.controller_name %>Controller < ApplicationController + def show + # Standard find by ID + <%= "@#{@scaffold.model_file_name}" %> = <%= @scaffold.model_name %>.find(params[:id]) + # Find by path + <%= "@#{@scaffold.model_file_name}" %> = <%= @scaffold.model_name %>.find_by_path(request.path) + if <%= "@#{@scaffold.model_file_name}" %> + render :show + else + render file: "#{Rails.root}/public/404.html", status: :not_found + Rails.logger.error "404 - Page #{request.path} cannot be found." + end + end +end diff --git a/lib/generators/atomic_cms/templates/model.erb b/lib/generators/atomic_cms/templates/model.erb new file mode 100644 index 0000000..b5da3d7 --- /dev/null +++ b/lib/generators/atomic_cms/templates/model.erb @@ -0,0 +1,4 @@ +class <%= @scaffold.model_name %> < ActiveRecord::Base + include AtomicCms::HasComponents + component_attr :content +end diff --git a/lib/generators/atomic_cms/templates/show.html.slim b/lib/generators/atomic_cms/templates/show.html.slim new file mode 100644 index 0000000..e367185 --- /dev/null +++ b/lib/generators/atomic_cms/templates/show.html.slim @@ -0,0 +1 @@ += <%= "@#{@scaffold.model_file_name}" %>.content_object.render