CMS Engine built for KPCC
Switch branches/tags
Nothing to show
Pull request Compare This branch is 145 commits behind SCPR:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Build Status

A Rails Engine for quickly standing up a CMS for a Newsroom.


  • rails >= 3.2
  • ruby >= 1.9.3

See .travis.yml to see which Ruby versions are officially supported.


Add gem 'outpost', github: 'SCPR/outpost' to your Gemfile.

This gem also has some hard dependencies that aren't in the gemspec. My goal is to reduce these dependencies as much as possible, but as this was extracted from the KPCC application, these are fairly strict at this point.

  • simple_form - for Rails 3.2, use ~> 2.1.0. For Rails 4.0, you'll need to use ~> 3.0.0.beta1
  • kaminari - You need to use the kaminari master branch.
  • eco
  • sass-rails
  • bootstrap-sass
  • coffee-rails



Much like Devise, Outpost provides a basic SessionsController and corresponding views. To use these, just add them to your routes:

namespace :outpost do
  resources :sessions, only: [:create, :destroy]
  get 'login'  => "sessions#new", as: :login
  get 'logout' => "sessions#destroy", as: :logout

Outpost also provides the Outpost::Model::Authentication module, which you should include into your User model to work with the provided SessionsController:

class User < ActiveRecord::Base
  include Outpost::Model::Authentication

Your User class should have at least the following methods:

  • password_digest (string)
  • last_login (datetime)
  • can_login (boolean)
  • is_superuser (boolean)
  • name (string)


You can set a different User class, or the attribute which the user should use to login:

Outpost::Config.configure do |config|
  config.user_class                   = "AdminUser"
  config.authentication_attribute     = :username

Note that this gem doesn't provide any routes for you. It is expected that you'll want to use the path globbing to render Outpost-style 404's inside of Outpost (rather than your application's 404 page), so it gets too messy and complicated to try to combine your routes with path globbing.

You'll want to put this at the bottom of you outpost namespace in your routes:

root to: 'home#dashboard'

resources :sessions, only: [:create, :destroy]
get 'login'  => "sessions#new", as: :login
get 'logout' => "sessions#destroy", as: :logout

get "*path" => 'errors#not_found'


Outpost comes with a built-in Permission model, whose only attribute is a String resource, which stores a class name which you want to be authorized throughout the application. Run this migration to set it up:

create_table :permissions do |t|
  t.string :resource

create_table :user_permissions do |t|
  t.integer :user_id
  t.integer :permission_id

add_index :permissions, :resource
add_index :user_permissions, :user_id
add_index :user_permissions, :permission_id

You can include Outpost::Model::Authorization into your User model to provide the Permission association, and also add the can_manage? method:

if !current_user.can_manage?(Post)
  redirect_to outpost_root_path, alert: "Not Authorized"

Authorization is "All-or-None"... in other words, a user can either manage a resource or not - A user with permission for a particular model is able to Create, Read, Update, and Delete any of those objects.

Outpost controllers will automatically authorize their resource. Within views, you can use one of the provided helpers to guard a block of text or a link:

<%= guard Post do %>
  Only users who are authorized for Posts will see this.
<% end %>

<%= guarded_link_to Post, "Linked if authorized, plaintext if not", posts_path %>

User Preferences

Preferences are stored in the session, and on a per-resource basis. Outpost provides built-in hooks in the controller and views for Order (attribute) and Sort Mode ("asc", "desc"). In order to manage other preferences, you'll want to make use of a handful of methods that get mixed-in to your Outpost controllers:

  • preference - Access a preference's value.
  • set_preference - Set a preference's value.
  • unset_preference - Unset a preference's value.

The key for a preference needs to follow the convention:


For example:

set_preference("blog_entries_color", "ff0000")

You also need to add the parameter that the preference is using to config.preferences:

Outpost::Config.configure do |config|
  # ...
  config.preferences += [:color]

A resource-based preference is automatically cleared if its param is an empty string (not nil). For example:

# GET /outpost/posts?color=ff0000
set_preference('posts_color', params[:color])
preference('posts_color') # => ff0000

# GET /outpost/posts?color=
preference('posts_color') # => nil

If you have a preference for a non-resourceful page, you need to manage its cleanup manually.


Outpost comes with a bunch of useful scripts built-in. Some of them are automatically used, and some are provided as "opt-in" functionality.

Field Counter

Field Counter

This will add a counter above any field which will show the number of characters entered into that field, the target length, and the +/- fuzziness, as well as a color indicating where in that range they are.


Add the class field-counter to a div wrapping the input field, and two data-attributes containing integers:

  • data-target - The target length (default: 145)
  • data-fuzziness - The fuzziness allowed (default: 20)

If you're using simple_form, it might look like this:

f.input :title, wrapper_html; { class: "field-counter", data: { target: 50, fuzziness: 10} }



The Javascript for Preview is what handles sending the form data to the server, but you'll need to handle the server-side stuff yourself. The "Preview" button will show up once you've added a preview action to that controller.


The preview action needs to do a few things:

  • Find the object from the passed-in obj_key (You can use Outpost::obj_by_key). You'll also need to handle what happens if the record hasn't been saved yet.
  • Merge in the changed attributes.
  • Render the proper template/layout, or any validation errors (using render_preview_validation_errors).
  • Make sure you don't save anything. For this, I recommend doing any object updating inside of a database transaction, because assigning associations to a persisted object will save the object. Outpost provides a controller method, with_rollback, which will perform the block inside of a database transaction and force an ActiveRecord::Rollback at the end.

Here is a full example of what your preview action could look like:

def preview
  @post = ContentBase.obj_by_key(params[:obj_key]) ||
  with_rollback @post do

    if @post.valid?
      render "/posts/_post", layout: "application", locals: { post: @post }

You'll also need to add two routes for the preview action:

resources :posts do
  put "preview", on: :member
  post "preview", on: :collection

You need both post and put to allow the preview to happen from either the New or Edit pages. If you're using Rails 4, use patch instead of put. In fact, if you're using Rails 4 (or the routing_concerns gem), then you can use Routing Concerns:

concern :previewable do
  patch "preview", on: :member
  post "preview", on: :collection

resources :posts, concerns: [:previewable]
resources :reporters, concerns: [:previewable]
resources :stories, concerns: [:previewable]

More documentation to come.


A ton of stuff. Here is a sampler:

  • Generators for resources (models, controllers).
  • Add record versioning (needs to be extracted from the SCPRv4 app).
  • Documentation... oh man, the documentation...


Pull Requests are encouraged! This engine was built specifically for KPCC, so its flexibility is limited... if you have improvements to make, please make them.

Fork it, make your changes, and send me a pull request.

Run tests with bundle exec rake test