I added a wiki to one of my sites. This may inspire you to create one yourself.
me@jaykilleen.com wrote this almost 8 years ago and it was last updated almost 8 years ago.
<%= bootstrap_form_for(@wiki_page, html: { class: 'form-horizontal' } ) do |f| %>
<fieldset>
<%= f.text_field :title %>
<%= f.text_area :content, :rows => 15, placeholder: "Write about this wiki" %>
<%= f.text_field :path %>
<%= f.text_field :wistia %>
<%= f.collection_select :parent_id, WikiPage.all, :id, :title, {:include_blank => ''}, class: 'form-control input-sm' %>
<%= f.text_field :tag_list, value: @wiki_page.tag_list.to_s, placeholder: "Add a comment", label: "Tags (separated by commas)", class: "form-control" %>
<div class="form-actions">
<%= f.button :submit, class: 'btn btn-success' %>
</div>
</fieldset>
<% end %>
<div id="wiki-side-panel" class='col-md-3'>
<div class="well well-sm" >
<div id="side-panel" class="panel panel-default">
<% if @wiki_page.present? %>
<div class="panel-heading"><h4>Wiki</h4></div>
<div class="panel-body">
<%= link_to 'Home', wiki_pages_path %>
</div>
<div class="panel-body">
<% if params[:action] != 'new' %>
<% if policy(@wiki_page).new? %>
<p><%= link_to 'New Wiki', new_wiki_page_path %></p>
<% end %>
<% else %>
<p><%= @wiki_page.back %></p></p>
<% end %>
</div>
<% if @wiki_page.parent != nil %>
<div class="panel-heading"><h4>Parent Page</h4></div>
<div class="panel-body">
<%= link_to @wiki_page.parent.title, wiki_page_path(@wiki_page.parent) %>
</div>
<% end %>
<% if @wiki_page.persisted? && @wiki_page.has_children? %>
<div class="panel-heading"><h4>Child Pages <span class="badge"><%= @wiki_page.children.count %></span></h4></div>
<% @wiki_page.children.each do |child_page| %>
<div class="panel-body">
<%= link_to child_page.title, wiki_page_path(child_page) %>
</div>
<% end %>
<% end %>
<% else %>
<div class="panel-heading"><h4>Wiki Pages</h4></div>
<% WikiPage.first(5).each do |wiki_page| %>
<div class="panel-body">
<%= link_to wiki_page.title, wiki_page_path(wiki_page) %>
</div>
<% end %>
<% end %>
</div>
<div id="wiki-tag-cloud" class="panel panel-default">
<div class="panel-heading"><h4>Most Used Tags</h4></div>
<div style="padding:5px;">
<% ActsAsTaggableOn::Tag.most_used(25).each do |tag| %>
<%= link_to tag.name, tag_path(tag.name) %>
<% end %>
</div>
</div>
</div>
</div>
<div class='col-md-12'>
<div id="wistia_<%= wistia_id %>" class="wistia_embed" style="width:640px;height:400px;"> </div>
<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js"></script>
<script>
wistiaEmbed = Wistia.embed('<%= wistia_id %>', {
videoFoam: true
});
</script>
<div class="page-header">
<h1>Editing Wiki Page</h1>
<p><%= @wiki_page.back %></p>
</div>
<div class="col-md-9">
<%= render 'form' %>
<p><%= @wiki_page.pun_destroy_link %></p>
</div>
<%= render 'side_panel' %>
source 'https://rubygems.org'
ruby '2.0.0'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.0'
gem 'passenger'
gem 'bcrypt', '~> 3.1.7'
gem 'devise', '~> 3.4.1'
gem 'pundit'
gem 'ancestry'
# Use postgresql as the database for Active Record
gem 'pg'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.3'
# All the things for Bootstrap Sass
gem 'bootstrap-sass', '~> 3.3.1'
gem 'bootstrap_form'
gem 'draper', '~> 1.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby
gem 'will_paginate', '~> 3.0.7'
gem 'will_paginate-bootstrap', '~> 1.0.1'
gem 'simple_form'
gem 'activerecord-session_store'
gem 'ransack', '~> 1.6.3'
# markdown in comments
gem 'html-pipeline', '~> 1.11.0'
gem 'github-markdown', '~> 0.6.7'
gem 'gemoji', '~> 2.1.0'
gem 'sanitize', '~> 3.0.3'
#wiki and tags
gem 'acts-as-taggable-on', '~> 3.4'
gem 'wistia-api', '~> 0.2.3'
group :development, :test do
gem 'minitest'
gem 'rspec', '~> 2.14'
gem 'rspec-rails'
gem 'capybara', '~> 2.2.0'
gem 'factory_girl_rails', '4.2.1'
gem 'faker'
gem 'launchy', '~> 2.1.2'
gem "shoulda-matchers", "~> 2.4.0"
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-commands-rspec'
gem 'jazz_hands'
gem 'pry-byebug'
end
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
# gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
group :doc do
gem 'sdoc', '~> 0.4.0', :require => false
end
group :development do
gem 'better_errors'
gem 'binding_of_caller'
gem 'annotate', '~> 2.6.5'
gem 'guard-rspec', require: false
gem 'web-console', '~> 2.0'
end
gem 'rails_12factor', group: :production do
gem 'capistrano', '~> 3.1'
gem 'capistrano-rails', '~> 1.1.1'
end
<% content_for :title, "Wiki" %>
<div class="page-header">
<h1><%= link_to 'Wiki', wiki_pages_path %></h1>
<small><p>Your complete guide to this app</p></small>
</div>
<div class="row">
<div class="col-sm-9">
<%= search_form_for @query, url: request.path, html: { class: "input-group customer-search-form"} do |f| %>
<% name = :title_or_content_cont %>
<%= f.text_field(name, :id => :query_field, :class => 'input form-control') %>
<span class="input-group-btn">
<%= button_tag(type: "submit", class: "btn btn-default", id: :search_button) do %>
<i class="glyphicon glyphicon-search"></i>
<% end %>
</span>
<% end %>
</div>
<div class="col-sm-3">
<%= link_to "Clear Search", request.path %>
</div>
</div>
<div class='col-md-9'>
<div class="text-center">
<div class="pagination centre">
<%= will_paginate @wiki_pages, renderer: BootstrapPagination::Rails %>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<tr>
<th><%= sort_link(@query, :title) %></th>
<th><%= sort_link(@query, :content) %></th>
<th>Video</th>
<th>Comments</th>
<th></th>
<th></th>
</tr>
<% policy_scope(@wiki_pages).each do |wiki_page| %>
<% wiki_page = wiki_page.decorate %>
<tr>
<td><%= link_to wiki_page.title, wiki_page_path(wiki_page) %></td>
<td><%= wiki_page.content[0..30] + "..." %></td>
<td><%= boolean_to_human(wiki_page.wistia.present?) %></td>
<td><%= wiki_page.comments.count %></td>
<% if policy(wiki_page).update? %>
<td><%= wiki_page.pun_edit_link %></td>
<% else %>
<td></td>
<% end %>
<% if policy(wiki_page).destroy? %>
<td><%= wiki_page.pun_destroy_link %></td>
<% else %>
<td></td>
<% end %>
</tr>
<% end %>
</table>
<div class="text-center">
<div class="pagination centre">
<%= will_paginate @wiki_pages, renderer: BootstrapPagination::Rails %>
</div>
</div>
<% if policy(@wiki_pages).new? %>
<%= link_to 'Create Wiki', new_wiki_page_path, class: 'btn btn-default' %>
<% end %>
</div>
</div>
<%= render 'side_panel' %>
<div class="page-header">
<h1>New Wiki Page</h1>
<p><%= @wiki_page.back %></p>
</div>
<div class="col-md-9">
<%= render 'form' %>
</div>
<%= render 'side_panel' %>
<% provide(:title, @wiki_page.title) %>
<div class="page-header">
<h1><%= @wiki_page.title %></h1>
<p><%= @wiki_page.back %></p>
</div>
<div class="col-md-9">
<small><p>Created by <%= @wiki_page.created_by_user_name + " " + @wiki_page.time_since_created %></p></small>
<small><p>Updated by <%= @wiki_page.updated_by_user_name + " " + @wiki_page.time_since_updated %></p></small>
<div class="bs-callout bs-callout-info">
<%= markdownify(@wiki_page.content) %>
</div>
<% if @wiki_page.wistia.present? %>
<div style="margin-right:5px;">
<%= render partial: "wistia_embed", locals: {wistia_id: @wiki_page.wistia} %>
</div>
<% end %>
<p>Tags: <%= raw @wiki_page.tag_list.map { |t| link_to t, tag_path(t) }.join(', ') %></p>
<% if policy(@wiki_page).update? %>
<%= link_to "Edit", edit_wiki_page_path(@wiki_page), class: 'btn btn-primary' %>
<% end %>
<%= render partial: "comments/comments", locals: {commentable: @wiki_page} %>
<%= render partial: "comments/form", locals: {commentable: @wiki_page} %>
</div>
<%= render 'side_panel' %>
require 'spec_helper'
feature 'User creates a wiki page' do
let(:wiki_page) { create(:wiki_page) }
let(:user) { create(:user) }
let(:super_admin) { create(:super_admin) }
before(:each) do
sign_in_as_user(super_admin)
end
scenario 'they can create a wiki from the index page' do
visit wiki_pages_path
click_link 'Create Wiki'
fill_in 'wiki_page_title', with: "A wiki"
fill_in 'wiki_page_content', with: "You know its a wiki"
click_button 'submit'
expect(WikiPage.last.title).to eql("A wiki")
end
scenario 'only super admin can create pages' do
change_user_role(user, 'account')
visit wiki_pages_path
click_link 'Create Wiki'
expect(page).to_not have_content("Create Wiki")
end
scenario 'even if they try and force their way in' do
change_user_role(user, 'account')
visit new_wiki_page_path
expect(page).to_not have_content("Create Wiki")
expect(page).to_not have_content("You cannot perform this action.")
end
end
# == Schema Information
#
# Table name: wiki_pages
#
# id :integer not null, primary key
# path :string
# title :string
# content :string
# ancestry :string
# created_by :integer
# updated_by :integer
# created_at :datetime
# updated_at :datetime
# wistia :string
#
class WikiPage < ActiveRecord::Base
has_ancestry
acts_as_taggable
# RELATIONSHIPS
has_many :comments, as: :commentable
belongs_to :user, :foreign_key => 'created_by'
# VALIDATIONS
validates_presence_of :title
validates_presence_of :content
# VALIDATIONS
#scope :has_video, where("wistia <> ''")
def created_by_user
user_id = self.created_by
if !user_id.blank?
author = User.find(user_id)
end
end
def updated_by_user
user_id = self.updated_by
if !user_id.blank?
updater = User.find(user_id)
end
end
end
class WikiPageDecorator < ApplicationDecorator
delegate_all
decorates_association :comments
# Define presentation-specific methods here. Helpers are accessed through
# `helpers` (aka `h`). You can override attributes, for example:
#
# def created_at
# helpers.content_tag :span, class: 'time' do
# object.created_at.strftime("%a %m/%d/%y")
# end
# end
def created_by_user_name
object.created_by_user.present? ? h.link_to(object.created_by_user.name, h.user_path(object.created_by_user)) : ""
end
def updated_by_user_name
object.updated_by_user.present? ? h.link_to(object.updated_by_user.name, h.user_path(object.updated_by_user)) : ""
end
def back
h.link_to 'Back', h.wiki_pages_path
end
def pun_edit_link
h.policy(object).update? ? h.link_to('Edit', h.edit_wiki_page_path(object)) : ""
end
def pun_destroy_link
h.policy(object).destroy? ? h.link_to('Destroy', object, method: :delete, data: { confirm: 'Are you sure?' } ) : ""
end
end
class WikiPagePolicy < ApplicationPolicy
class Scope < Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
scope.all unless @user.blocked?
end
end
def show?
return true unless @user.blocked?
end
def create?
return true if @user.super_admin?
end
def new?
create?
end
def update?
return true if user.super_admin?
end
def edit?
update?
end
def destroy?
return true if user.super_admin?
end
end
require 'spec_helper'
require 'pundit/rspec'
describe WikiPagePolicy do
let!(:user) { create(:user) }
let!(:super_admin) { create(:super_admin) }
let!(:blocked_user) { create(:blocked_user) }
subject { WikiPagePolicy }
permissions ".scope" do
end
permissions :index? do
end
permissions :create? do
it "grants access if user is super admin" do
expect(subject).to permit(super_admin)
end
it "rejects access to everyone else" do
#rejects
expect(subject).to_not permit(user)
expect(subject).to_not permit(blocked_user)
end
end
permissions :show? do
it "grants access if user is super admin" do
expect(subject).to permit(super_admin)
end
it "rejects access if user is blocked" do
expect(subject).not_to permit(blocked_user, supplier)
end
end
permissions :update? do
it "grants access if user is super admin" do
expect(subject).to permit(super_admin)
end
end
permissions :destroy? do
it "grants access if user is super admin" do
expect(subject).to permit(super_admin)
end
end
end
class WikiPagesController < ApplicationController
before_action :authenticate_user!
before_action :redirect_blocked_user
before_action :set_wiki_page, only: [:show, :edit, :update, :destroy]
after_filter :verify_authorized, except: :index
after_filter :verify_policy_scoped, only: :index
def index
if params[:tag]
@query = policy_scope(WikiPage.tagged_with(params[:tag])).ransack(params[:q])
@wiki_pages = @query.result(distinct: true).paginate(:page => params[:page])
else
@query = policy_scope(WikiPage).ransack(params[:q])
@wiki_pages = @query.result(distinct: true).paginate(:page => params[:page])
end
end
def show
authorize @wiki_page
@wiki_page = @wiki_page.decorate
end
def new
@wiki_page = WikiPage.new.decorate
authorize @wiki_page
end
def edit
authorize @wiki_page
@wiki_page = @wiki_page.decorate
end
def create
@wiki_page = WikiPage.new(wiki_page_params)
@wiki_page.created_by = current_user.id
authorize @wiki_page
respond_to do |format|
if @wiki_page.save
format.html { redirect_to @wiki_page, notice: 'WikiPage was successfully created.' }
else
format.html { render :new }
end
end
end
def update
@wiki_page.updated_by = current_user.id
authorize @wiki_page
respond_to do |format|
if @wiki_page.update(wiki_page_params)
format.html { redirect_to @wiki_page, notice: 'WikiPage was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
authorize @wiki_page
@wiki_page.destroy
respond_to do |format|
format.html { redirect_to wiki_pages_url, notice: 'WikiPage was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_wiki_page
@wiki_page = WikiPage.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def wiki_page_params
params.require(:wiki_page).permit(:title, :content, :path, :wistia, :parent_id, :tag_list, :created_by, :updated_by)
end
end
module WikiPagesHelper
def wistia_embed
Wistia.embed(@wiki_page.wistia, {
videoFoam: true
});
end
end
require "spec_helper"
describe WikiPagesController do
describe "routing" do
it("routes to #index") { get("/wiki_pages").should route_to("wiki_pages#index") }
it("routes to #show") { get("/wiki_pages/1").should route_to("wiki_pages#show", :id => "1") }
it("routes to #new") { get("/wiki_pages/new").should route_to("wiki_pages#new") }
it("routes to #create") { post("/wiki_pages").should route_to("wiki_pages#create") }
it("routes to #edit") { get("/wiki_pages/1/edit").should route_to("wiki_pages#edit", :id => "1") }
it("routes to #update") { put("/wiki_pages/1").should route_to("wiki_pages#update", :id => "1") }
it("routes to #destroy") { delete("/wiki_pages/1").should route_to("wiki_pages#destroy", :id => "1") }
end
end
class CreateWikiPages < ActiveRecord::Migration
def change
create_table :wiki_pages do |t|
t.string :path
t.string :title
t.string :content
t.string :ancestry
t.integer :created_by
t.integer :updated_by
t.timestamps
end
end
end