-
-
Notifications
You must be signed in to change notification settings - Fork 406
How to create a plugin
Plugins are a work in progress. Suggestions are welcome!
Plugins allow you to share and reuse common features. In this guide we're going to create a plugin called 'events'.
From an existing Spina app, run the rails generator for a 'full' rails engine:
rails plugin new vendor/plugins/events --full
This will create an engine inside your 'vendor/plugins' directory. Update the newly created gemspec with your contact information and add Spina as a dependency:
# /vendor/plugins/events/events.gemspec
Gem::Specification.new do |s|
s.name = "events"
s.version = Events::VERSION
s.authors = ["Your name"]
s.email = ["[email protected]"]
s.homepage = "http://www.spinacms.com/"
s.summary = "Summary of Events."
s.description = "Description of Events."
s.license = "MIT"
s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
s.test_files = Dir["test/**/*"]
s.add_dependency "rails"
s.add_dependency "spina"
s.add_development_dependency "sqlite3"
end
In order to register the plugin on Spina configuration, update the vendor/plugins/events/lib/events/engine.rb
with the following lines:
require 'spina'
module Events
class Engine < ::Rails::Engine
initializer 'spina.plugin.register.events', before: :load_config_initializers do
::Spina::Plugin.register do |plugin|
plugin.name = 'events'
plugin.namespace = 'events'
end
end
end
end
First generate the model events inside the engine. Go to the plugin directory and run the generator:
cd vendor/plugins/events
rails g model spina/event title:string description:text date:datetime
We want to be able to manage our new resource inside the Spina admin. Add the following routes:
# /vendor/plugins/events/config/routes.rb
Spina::Engine.routes.draw do
namespace :admin, path: Spina.config.backend_path do
resources :events, except: [:show]
end
end
Notice that you have to change Events::Engine.routes.draw
to Spina::Engine.routes.draw
. This will add the routes to the existing Spina engine instead of the rails app.
Create the events controller:
# /vendor/plugins/events/app/controllers/spina/admin/events_controller.rb
module Spina
module Admin
class EventsController < AdminController
before_action :set_breadcrumb
before_action :set_event, only: [:edit, :update, :destroy]
admin_section :events
layout 'spina/admin/admin'
def index
@events = Event.all
end
def new
@event = Event.new
end
def edit
end
def create
@event = Event.new(event_params)
if @event.save
redirect_to admin_events_path, notice: 'Event was successfully created.'
else
render :new
end
end
def update
if @event.update(event_params)
redirect_to admin_events_path, notice: 'Event was successfully updated.'
else
render :edit
end
end
def destroy
@event.destroy
respond_to do |format|
redirect_to admin_events_path, notice: 'Event was successfully destroyed.'
end
end
private
def event_params
params.require(:event).permit(:title, :description, :date)
end
def set_breadcrumb
add_breadcrumb 'Events', admin_events_path
end
def set_event
@event = Event.find(params[:id])
add_breadcrumb @event.title
end
end
end
end
Add the following views:
-# /vendor/plugins/events/app/views/spina/admin/events/index.html.haml
.filters
= link_to 'New event', spina.new_admin_event_path, class: 'button button-primary', data: {icon: 't'}
.table-container
%table.table
%thead
%tr
%th Title
%th Date
%th
%tbody
- if @events.any?
- @events.each do |event|
%tr
%td
= event.title
%td
= l(event.date)
%td.nowrap.align-right
= link_to spina.edit_admin_event_path(event), class: 'button button-link' do
= icon('pencil-outline')
- else
%tr
%td.align-center{colspan: 3}
%em There are no events
-# /vendor/plugins/events/app/views/spina/admin/events/_form.html.haml
= form_for [:admin, @event], html: {autocomplete: "off"} do |f|
- content_for :notification_alert do
= error_explanation!(@event)
#page_content
.table-container
%table.table.table-form
%tr
%td
Title
%td
= f.text_field :title
%tr
%td
Description
%td
= f.text_area :description
%tr
%td
Date
%td
= f.text_field :date, value: (@event.date.strftime("%d-%m-%Y") unless @event.new_record?), class: 'datepicker'
%button.button.button-primary{type: 'submit', data: {icon: 'o'}}
Save
= link_to 'Cancel', admin_events_path, class: 'button button-link'
- unless @event.new_record?
.pull-right= link_to 'Delete', admin_event_path(@event), method: :delete, confirm: 'Are you sure?', class: 'button button-link button-danger'
-# /vendor/plugins/events/app/views/spina/admin/events/new.html.haml
= render 'form'
-# /vendor/plugins/events/app/views/spina/admin/events/edit.html.haml
= render 'form'
Next we want to add links to our new resource. Spina provides 'hooks' to add your own views to existing layouts. During the rendering of a layout, Spina will search for a view with a specific name in the hooks directory. If such a view exists, then Spina will render the view. For now the following hooks are available:
- [plugin-root]/app/views/spina/admin/hooks/[plugin-name]/_primary_navigation.html.haml
- [plugin-root]/app/views/spina/admin/hooks/[plugin-name]/_website_secondary_navigation.html.haml
- [plugin-root]/app/views/spina/admin/hooks/[plugin-name]/_settings_secondary_navigation.html
For this example we're going to add links to the 'Your website' menu by creating the following view:
-# vendor/plugins/events/app/views/spina/admin/hooks/events/_website_secondary_navigation.html.haml
%li{ class: ('active' if current_admin_path.start_with?('/events')) }
= link_to spina.admin_events_path do
= plugin.name
The final result will look like this:
Add the gem to the Gemfile to your main rails app:
gem 'events', path: 'vendor/plugins'
Now you will be able to install the gem with bundle install
, copy and install the migrations and restart your server.
bundle install
rake events_engine:install:migrations
rake db:migrate
touch tmp/restart.txt
and add the plugin to your themes/default.rb file
theme.plugins = ['events']