Spree is one of the most popular open-source eCommerce platforms build with Ruby on Rails. Spree is popular for its modularity and flexibility in building and managing the store.
Github: https://github.com/spree/spree
Spree provides a robust and clean admin interface to manage the commerce and different resource although it might need to manage the new resource by admin. In order to manage the new resource by admin user, there needs to create a Admin Tabs/Menu. Here we will learn how to create a Admin Tabs/Menu for the new resources.
Deface for adding Tab
Deface is a library that allow to customize HTML (Erb, Haml, Slim) views in Rails application without editing the underlying view.
Adding New Resource
Let’s add a new resource called Subscription
and allow an admin user to perform CRUD operations on a subscription.
Create a model and migration file.
rails generate migration CreateSubscriptions
# above command will create a file with this content in your db/migrate folder
class CreateSubscriptions < ActiveRecord::Migration[6.1]
def change
create_table :spree_subscriptions do |t|
t.string :name
t.integer :duration_in_month
t.integer :status, null: false, default: 0
t.timestamps
end
end
end
Execute rake db:migrate
to create the table in database and updates the schema.rb
.
Create a model.
# app/models/subscription.rb
module Spree
class Subscription < ApplicationRecord
scope :active, -> { where(status: :active) }
enum status: { inactive: 0, active: 1 }
end
end
Create an admin tab using deface.
# app/overrides/admin_subscription.rb
Deface::Override.new(
name: 'subscription_tab',
virtual_path: 'spree/admin/shared/_main_menu',
insert_after: '#sidebarProduct',
partial: 'spree/admin/shared/subscription_menu'
)
Subscription Menu Partial
# app/views/spree/admin/shared/subscription_menu.html.erb
<% if can? :manage, Spree::Subscription %>
<ul class="nav nav-sidebar border-bottom" id="sidebarSubscriptions">
<%= tab 'Subscriptions', icon: "icon.svg", sub_menu: "services", url: "admin_subscriptions_path" %>
</ul>
<% end %>
Routes and Controllers
# config/routes.rb
Spree::Core::Engine.routes.draw do
namespace :admin do
resources :subscriptions
end
end
# app/controllers/spree/admin/subscriptions_controller.rb
module Spree
module Admin
# Aside from index, using the inherited actions as they are sufficient.
class SubscriptionsController < Spree::Admin::ResourceController
</predef index
@subscriptions = Spree::Subscriptions.active
end
end
</pre>
end
</pre>
end
</pre>
Views
# app/views/spree/admin/subscriptions/index.html.erb
<% content_for :page_title do %>
Subscriptions
<% end %>
<% if can? :manage, Spree::Subscriptions %>
<% content_for :page_actions do %>
<%= button_link_to 'New Subscription', new_admin_subscription_path, class: 'btn-success', icon: 'add.svg', id: 'new-admin-subscription' %>
<% end %>
<% end %>
<table class="table sortable" data-hook="subscriptions_table" data-sortable-link="<%= update_positions_admin_subscriptions_url %>">
<thead>
<tr data-hook="subscriptions_header">
<th>Name</th>
<th>Duration</th>
<th>Status</th>
<th class="actions"></th>
</tr>
</thead>
<tbody>
<% @subscriptions.each do |subscription| %>
<tr id="<%= spree_dom_id subscription %>" data-hook="subscriptions_row">
<td><%= subscription.name %></td>
<td><%= subscription.duration_in_month %> month</td>
<td><%= subscription.status %></td>
<td class="actions actions-2 text-right">
<%= link_to_edit subscription, no_text: true, class: 'edit' if can?(:edit, subscription) %>
<!-- Add translation icon support -->
<%= link_to_with_icon 'translate',
nil,
spree.admin_translations_path('subscription', subscription.id),
title: Spree.t(:'i18n.translations'),
class: 'btn btn-sm btn-primary' if defined? (SpreeGlobalize)%>
</td>
</tr>
<% end %>
</tbody>
</table>
# app/views/spree/admin/subscriptions/_form.html.erb
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @subscription } %>
<div class="form-group">
<%= form_for [:admin, @object] do |form| %>
<%= f.field_container :name do %>
<%= f.label :name, 'Name' %>
<%= f.text_field :name, required: true %>
<% end %>
<%= f.field_container :duration_in_month do %>
<%= f.label :duration_in_month, 'Duration In Month' %>
<%= f.text_field, :duration_in_month, required: true %>
<% end %>
<%= f.field_container :status do %>
<%= f.label :status %>
<%= f.radio_button :status, :active %>
<%= f.label :status, 'Active', :value => :active %>
<%= f.radio_button :status, :inactive %>
<%= f.label :status, 'Inactive', :value => :inactive %>
<% end %>
<div class="form-actions" data-hook="buttons">
<%= button (@object.persisted? ? Spree.t('actions.update') :
Spree.t('actions.create')), 'save.svg' %>
<span class="or"><%= Spree.t(:or) %></span>
<%= button_link_to Spree.t('actions.cancel'), admin_subscriptions_path, icon: "cancel.svg" %>
</div>
<% end %>
</div>
# app/views/spree/admin/new.html.erb
<% content_for :page_title do %>
<%= link_to plural_resource_name(Spree::Subscription),
spree.admin_subscriptions_url %> /
New Subscription
<% end %>
<%= form_for [:admin, @subscription] do |f| %>
<fieldset>
<%= render partial: 'form', locals: { f: f } %>
<%= render partial: 'spree/admin/shared/new_resource_links' %>
</fieldset>
<% end %>
# app/views/spree/admin/edit.html.erb
<% content_for :page_title do %>
<%= link_to plural_resource_name(Spree::Subscription),
spree.admin_subscriptions_url %> /
<%= @subscription.name %>
<% end %>
<%= form_for [:admin, @subscription] do |f| %>
<fieldset>
<%= render partial: 'form', locals: { f: f } %>
<%= render partial: 'spree/admin/shared/edit_resource_links' %>
</fieldset>
<% end %>
That’s it! Once the above is in place, restart your app for good measure and you will see a “Subscriptions” menu in your admin area. From there, you’ll have control over your Subscription
records.