ActiveScaffold Sortable
ActiveScaffold Sortable adds AJAX drag-and-drop ordering to Active Scaffold lists and association subforms. It supports ordinary ordered lists, automatic configuration for acts_as_list models, and sibling ordering in nested-set and Ancestry trees.
Requirements
- Ruby 2.0 or newer
- Active Scaffold 4.4.0 or newer
- A Rails version supported by the selected Active Scaffold version
- jQuery UI Sortable on pages that use the plugin
For Rails 3 applications, use an active_scaffold_sortable 3.2.x release.
Installation
Add the following line to your Gemfile:
gem 'active_scaffold_sortable'Then run:
bundle installThe engine automatically registers the Active Scaffold action, route, JavaScript, stylesheet, and view overrides.
Ordered lists
With acts_as_list
Add a position column and configure the model with acts_as_list:
class AddPositionToEntries < ActiveRecord::Migration[6.0]
def change
add_column :entries, :position, :integer
add_index :entries, :position
end
endclass Entry < ApplicationRecord
acts_as_list
endThe plugin detects acts_as_list, enables the :sortable action, and uses the model’s configured position column. No Active Scaffold controller configuration is required.
Scopes configured in acts_as_list still define separate logical lists. A rendered Active Scaffold list should contain records from only one scope, so dragging cannot mix independent lists.
Without acts_as_list
Sorting can use any persisted column that accepts one-based integer positions. Enable the action and select the column explicitly:
class EntriesController < ApplicationController
active_scaffold :entry do |config|
config.actions << :sortable
config.sortable.column = :position
end
endAfter every drop, the visible records receive consecutive positions beginning at 1. The plugin updates records directly with update_all, so model validations and callbacks do not run. It also updates updated_at when that column exists. The reorder action uses Active Scaffold’s update authorization check.
Sortable association subforms
A collection association is draggable in a create or update form when the associated model’s Active Scaffold configuration includes :sortable. This works whether sorting was enabled automatically by acts_as_list or configured manually:
class TasksController < ApplicationController
active_scaffold :task do |config|
config.actions << :sortable
config.sortable.column = :position
end
endFor example, a Project form that renders a has_many :tasks subform will allow its task rows to be reordered. Dragging changes the hidden position fields in the form; the new order is persisted when the parent form is submitted, rather than through a separate reorder request. New associated records without a position are placed after the highest existing position.
Only collection associations are sortable. The associated scaffold may omit the :list action when sorting is needed only in a subform.
Tree models
Tree support reorders nodes only among their current siblings. It does not move a node to a different parent.
Nested sets (awesome_nested_set)
Models using awesome_nested_set are detected automatically:
class Category < ApplicationRecord
acts_as_nested_set
endThe plugin enables :sortable, uses the model’s configured left column, and calls the nested-set movement methods to preserve valid left and right bounds. Root nodes can also be reordered as siblings.
Detection is API-based. Another nested-set implementation may work if it provides nested_set_scope, left_column_name, self_and_siblings, move_left, and move_right, but awesome_nested_set is the supported integration.
Ancestry
Ancestry models are recognized during reordering, but sorting is not enabled automatically. Add a separate position column and configure it explicitly:
class Category < ApplicationRecord
has_ancestry
endclass CategoriesController < ApplicationController
active_scaffold :category do |config|
config.actions << :sortable
config.sortable.column = :position
end
endBoth root nodes and children can be reordered within the first submitted record’s sibling set. Do not use the ancestry column as the sortable column: it stores a path, not a sibling position.
Configuration
Drag handle
The whole row is the drag handle by default. To add a dedicated handle column at the beginning or end of the list:
config.sortable.add_handle_column = :first
# or
config.sortable.add_handle_column = :lastThe accepted values are :first, :last, and false/nil.
Refresh after reordering
The default response only reapplies alternating row styles. Refresh the entire list after each reorder when other displayed values depend on the order:
config.sortable.refresh_list = trueAdvanced DOM options
config.sortable.options is merged into the sortable container’s data-* attributes. The supported overrides are integration hooks for custom Active Scaffold markup:
config.sortable.options = {
tag: "> tr", # selector for draggable items
handle: ".my-drag-handle", # selector that starts dragging
content_selector: ".my-records", # sortable content in the container
key: "as_entries-tbody", # serialized parameter base
format: "^[^_-].*-(.*)-row$", # extracts the record ID from a row ID
with: "scope_id=42" # extra reorder request parameters
}These options are not a general pass-through for every jQuery UI Sortable setting. If you override key, keep it aligned with the parameter name expected by the reorder action.
You can also define defaults for every sortable scaffold in an initializer, before Active Scaffold configurations are built:
ActiveScaffold::Config::Sortable.add_handle_column = :first
ActiveScaffold::Config::Sortable.refresh_list = true
ActiveScaffold::Config::Sortable.options = { handle: ".my-drag-handle" }UI adapter support
ActiveScaffold Sortable 3.7 exposes the wrapper around sortable lists and association subforms as the sortable_container UI element. The same adapter configuration applies in both contexts:
ActiveScaffold.add_element_attributes :sortable_container,
class: "overflow-auto"The default tag is div; an adapter can change it when its markup requires a different container:
ActiveScaffold.set_element_tag :sortable_container, :sectionAdapter attributes are merged with the sortable-container class and the data-* attributes used for drag-and-drop behavior. See Customizing UI Markup and Integrating CSS Frameworks for the complete UI adapter API.
Effects on the Active Scaffold list
Enabling :sortable also:
- Disables pagination so every draggable record is present in one list
- Orders the list by the sortable column in ascending order
- Disables sorting by other columns
- Hides the sortable column from normal action columns, while retaining it as a hidden field in subforms
The browser submits only rendered rows. Filters and nested views therefore update only the visible subset, while records not shown retain their stored positions. In an ordinary list this can produce duplicate positions. Keep each sortable view within one logical list or sibling set, and use filtering with care.
Support
For help, use the Active Scaffold discussion group or open an issue.
