Skip to content

Instantly share code, notes, and snippets.

@alexey
Last active August 7, 2020 08:34
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexey/446c6c4ce2a5af0f4fb6851e6d6d514e to your computer and use it in GitHub Desktop.
Save alexey/446c6c4ce2a5af0f4fb6851e6d6d514e to your computer and use it in GitHub Desktop.
ActiveAdmin + CanCan + AASM event switcher with AJAX

About:

Inspired by activeadmin_addons and its Enum Integration I want to make similar functionality for AASM by letting users change events depending on their abilities and available events/statuses in model.

Sorry i have no time to create an addon right now for this gem but i will try to do it soon. Feel free to modify, use it and integrate. Ask me any question if you need!

Prequestites:

Gem: ActiveAdmin, Gem 'active_admin_role', both are installed and working AdminUser model with current_admin_user setup (or similar to your app).

Tested with Rails 5.1.3.

After you finish and deploy/run server you must "Reload" Permissions in admin and enable "event_update" for manager or other than "super_admin" roles.

Smaller addons you'll need to do:

(in addition to below attached files)

In your AdminUser model add:

  include CanCan::Ability
  include ActiveAdminRole::CanCan::Ability

In your table_for (is where you render columns of data)

    column 'Our Status' do |auction|
      render 'admin/auctions/event_change', auction: auction
    end

In initializers/active_admin.rb or whenever you want

ActiveAdmin::ResourceController.class_eval do
  protected

  def current_ability
    # Match to your current admin user
    @current_ability ||= Ability.new(current_admin_user)
  end
end

also make sure your config:

  config.authorization_adapter = ActiveAdmin::CanCanAdapter
  config.authorization_adapter = ActiveAdmin::CanCanAdapter
  config.cancan_ability_class = 'Ability'

Pardon me if I forgot something, let me know if you have any question or problem !!

# This is the partial that rendered from admin auctions index, column of "Status"
# You have to pass in auction object
- permitted_any = auction.aasm.events(permitted: true).map &:name
- possible_events = []
- permitted_any.each do |event|
- next unless can?(event, Auction)
- possible_events << event
- if possible_events.any?
.events-wrap
%div{ class: 'current-state status_tag ' + auction.status, id: dom_id(auction) + '_event' }
= auction.status
.new-events{ 'data-url' => update_event_admin_auction_path(auction) }
- possible_events.each do |new_event|
.set-event.status_tag{ class: new_event, 'data-event' => new_event }
= new_event
- else
.status_tag{ class: auction.status }
= auction.status
# This is example for abilities, please put your own events
if user.super_user?
can :manage, :all
# Must match events in Auction model and to css styling
can [:set_pending, :set_go, :set_pass, :set_suggest_go, :set_suggest_pass], Auction
end
if user.manager?
can [:set_suggest_go, :set_suggest_pass], Auction
end
# This is example from project i've implemented.
# Make sure you match event names and status names to css and Ability class permissions
enum status: {
not_checked: 0,
suggest_go: 2,
suggest_pass: 5,
go: 12,
pass: 15
}
aasm column: :status, enum: true do
state :not_checked, initial: true
state :suggest_go
state :suggest_pass
state :go
state :pass
# By super admin
event :set_pending do
transitions to: :not_checked, from: %i[go pass suggest_go suggest_pass]
end
event :set_go do
transitions to: :go, from: %i[not_checked pass suggest_go suggest_pass]
end
event :set_pass do
transitions to: :pass, from: %i[not_checked go suggest_go suggest_pass]
end
# Manager should be able to do only those events
event :set_suggest_go do
transitions to: :suggest_go, from: %i[not_checked suggest_pass pass]
end
event :set_suggest_pass do
transitions to: :suggest_pass, from: %i[not_checked suggest_go go]
end
end
ActiveAdmin.register Auction do
permit_params :status
member_action :update_event, method: :post do
to_event = params[:event]
if can?(to_event.to_sym, Auction)
@auction = Auction.find(params[:id])
if @auction.send(to_event + '!')
render partial: 'admin/auctions/event_change', locals: { auction: @auction }
else
render text: :error
end
else
render text: :denied
end
end
end
# Put this somewhere in your activeadmin coffee files. You know how to put in onload right ?
$(document).on 'click', '.set-event', ->
update_td = $(@).closest('td')
url = $(@).parent().data('url')
event = $(@).data('event')
$(@).closest('.events-wrap').html('Saving...')
$.post url, { event: event }, (data) ->
update_td.html(data)
// This is to define styling:
.current-state, .set-event{
cursor: pointer;
}
.events-wrap{
position: relative;
.new-events{
background-color: #EEE;
border-radius: 5px;
border: 1px solid #444;
display: none;
padding: 9px;
z-index: 100;
position: absolute;
.set-event{
border-left: 2px solid transparent;
border-right: 2px solid transparent;
&:hover, &:active{
border-left: 2px outset slateblue;
border-right: 2px outset slateblue;
}
}
}
// make events appear on hover
&:hover, &:active{
.new-events{
display: block;
}
}
}
// This is to colorize your events and statuses
// Set colors for auction status.
// You have to colorize both event name and status name
$not_checked-color: #DDAA55;
$pass-color: #FF0000;
$go-color: #08A510;
$suggest-go-color: #A8FFA0;
$suggest-pass-color: #FFA8A0;
.status_tag {
&.not_checked, &.set_pending { background: $not_checked-color; }
&.pass, &.denied, &.set_pass { background: $pass-color; }
&.go, &.allowed, &.set_go { background: $go-color; }
&.suggest_pass, &.set_suggest_pass { background: $suggest-pass-color; color: #444; }
&.suggest_go, &.set_suggest_go { background: $suggest-go-color; color: #444; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment