Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
  app
  config
  db
  lib
  vendor
  README.md
  Rakefile
Size: Mime:
  README.md

Evergreen

Nestable pages engine for Rails from your pals at Neoteric Design, Inc.

Getting Started

Installation

# Gemfile
gem 'evergreen', '~> 4.2.0'
$ bundle install
$ rails g evergreen:install
$ rake db:migrate db:test:prepare

Configuration

Evergreen.admin_ui = :active_admin

Turn on ActiveAdmin Support

Evergreen.root_page_class = :page

Page class to use for Error Handling

Usage

Out of the box, you get a Page model and a PagesController configured to use Evergreen. To create additional Page types, inherit a new model from Evergreen::Page

class Page < Evergreen::Page

end

class PagesController < ApplicationController
  evergreen
end

System Pages

Evergreen lets you define special Pages that can be defined and accessed programatically. By default you're set up with a home_page and Error handling pages.

Say you have an Events section and you want to have a page to represent it in the navigation, as well as some evergreen content to be displayed.

class Page < Evergreen::Page
 register_system_page :not_found, "Page Not Found"
 register_system_page :events, "Upcoming Events"
end

Now Page will have a class method events_page, that will either find or initialize a new page instance by that title 'Upcoming Events'. This means anywhere in your application you can consistently work with Page.events_page without worrying if it exists in the database, and users can save and edit its contents with gleeful abandon (as long as the title matches).

Strong parameters

Evergreen provides a helper to help whitelisting its form attributes.

ActiveAdmin:

permit_params Evergreen.params

Standard controller:

params(:page).permit(Evergreen.params)

Routing

Evergreen now just needs one route statement per class. Say you had two kinds of pages, regular Page, and some kind of protected PrivatePage.

root to: 'pages#home'

scope 'private' do
  root to: 'private_pages#home'
  get '*path' => 'private_pages#show', as: :private_page
end

get '*path' => 'pages#show', :as => :page

You can use scopes or prefixes, but scopes are preferred so you can cleanly set a root 'home' page. The routes should use a wildcard path. Naming the route after the model lets Linking Just Work. Pages only store their relative path, so page look up is as easy as find_by_path(params[:path]) with Rails matching the route by model name (unless you explicitly specify it.

Remember routes are read line by line so the more general, root Page should go last!

Linking

<%= link_to page.navigation_label, page %>
<%= link_to page.navigation_label, page_path(page) # Explicitly state route %>

The page model

Instance methods

Method name Description
title Page title
navigation_label Label used for navigation links. Defaults to title
path Path used for Routing
body Body content
hidden Boolean value for whether the page should be listed in nav
drafted Boolean value for whether the page is publicly accessible
state "published" or "drafted" state as a string.
meta_description Meta description for page head
slug Slugified navigation label (or title) for generated paths
update_path! Regenerates path (and updates the DB), returns the new path

Class methods

Method name Description
find_by_path(path) Look up by relative path, can throw RecordNotFound
register_system_path(identifier, title See System Pages

Scopes

Name Description
published Publicly accessible pages, including hidden pages
visible Publicly accessible pages, excluding hidden pages

Helpers

home?

  • Check if rendering a home page

browser_title(*titles)

  • Build a browser page title.
browser_title('Site Name')
#=> 'Site Name'
browser_title('Site Name', 'Some Section', @page.title)
#=> 'The Page Title - Some Section - Site Name'

state_label(state)

  • Builds a span tag with a given state, and classes of state-label and state

drafted_label(page)

  • Builds a state label for the Admin UI if the page is drafted

hidden_label(page)

  • Builds a state label for the Admin UI if the page is hidden

Admin UI labels

drafted_label(@page)
#=> "<span class='state-label drafted'>Drafted</span>" if @page.drafted?
hidden_label(@page)
#=> "<span class='state-label hidden'>Hidden</span>" if @page.hidden?

Controller actions

class YourPagesController < ApplicationController
  evergreen
end

Provides the following actions:

# page_class is determined from controller name, override if necessary
def home
  @page = page_class.home_page
end

def show
  @page = page_class.visible.find_by_path(params[:path])
end

Error Handling

Evergreen provides some helpful error handling methods within your controllers. Make sure Evergreen.root_page_class is set in your initializers, or override the root_page_class method in your controllers. This is the class these methods will use to look up the system pages. These get called by the rescue_from statements dropped into your ApplicationController. Don't like em? Remove the lines! Or override them! You do you.

not_found

  • Renders the not_found_page system page, with a 404 status. By default used for unmatched routes and missing templates.

server_error(exception)

  • Renders the server_error_page system page with a 500 status. By default used when an exception is caught.

log_error(exception)

  • Used by server_error to send info to the Rails logger. Override this method as you see fit.

report_error(exception)

  • Used by server_error to report errors (default to Raygun if present). Override this method as you see fit.

render_error_options

  • Hash passed to the render method inside server_error. By default makes sure errors are rendered with the 'application' layout and 'pages/show' template. Override as you see fit.

ActiveAdmin Integration

You must have ActiveAdmin installed first!

$ rails g evergreen:active_admin
ActiveAdmin.register Page do
  evergreen_activeadmin
end

See lib/evergreen/core_ext/active_admin for everything it's providing under the hood.

Testing

Evergreen provides an RSpec linter for your models

describe Page, type: :model do
  include Evergreen::SpecHelpers::Lint
end

Running the gem's test suite:

$ rspec

TODO

  • Remove compass-rails as dependency
  • Refactor ActiveAdmin Integration into discrete components
  • Start a changelog
  • Reduce DB thrashing when using sortable tree. Still preferable to the old way of thrashing the DB upon every. single. lookup. But we can do better!
  • Add generating of routing test for post-install

Further Reading and Thanks