Drag and drop to re-order
Katalyst::Tables::Orderable
adds the ability to bulk-update an ordinal column for model instances from an index table view. Users can drag and drop rows within their table and the extension will automatically patch the configured URL with the new ordering data.
Usage
The extension is included by default and can be enabled for a specific table by adding an ordinal
column:
<%= table_with(collection:) do |row| %>
<% row.ordinal %>
<% row.text :name %>
<% end %>
By default, ordinal columns render a ⠿
icon to the cell. This can be configured by setting I18n for katalyst.table.orderable.value
.
You will also need to create a hidden form for holding and submitting changes to the ordinal data when the user interacts with the table:
<%= table_orderable_with(collection:, url: order_models_path) %>
The url
argument is required. When a user interacts with the table elements, this URL will be patched with changes to the ordering.
Index tables
Orderable can be used to add drag-and-drop ordering to an index table. The minimal example for a controller that supports saving ordinal index table data looks like this:
Routes
resources :models do
patch :order, on: :collection
end
Model
class Model < ApplicationRecord
attribute :orderable, :integer
default_scope { order(orderable: :asc) }
end
Controller
def index
render locals: { collection: Model.all }
end
def order
order_params[:models].each do |id, attrs|
Model.find(id).update(attrs)
end
redirect_back(fallback_location: models_path, status: :see_other)
end
private
def order_params
params.require(:order).permit(models: [:ordinal])
end
View
<%= table_with(collection:) do |row| %>
<% row.ordinal %>
<% row.text :name %>
<% end %>
<%= table_orderable_with(collection:, url: order_models_path) %>
Nested association tables
You can also use Orderable to add drag-and-drop ordering for an association. In this example, we use a component, but the same approach can be used with the extend method as above.
In this example, we’re assuming that the model has a nested images association and supports nested attributes via update. We’re also assuming that the images table is providing a default stable sort based on the ordinal
attribute.
Routes
resources :galleries
Model
class Gallery < ApplicationRecord
has_many :images
accepts_nested_attributes_for :images
end
class Image < ApplicationRecord
belongs_to :gallery
attribute :orderable, :integer
default_scope { order(orderable: :asc) }
end
Controller
def show
@gallery = Gallery.find(params[:id])
end
def update
@gallery = Gallery.find(params[:id])
@gallery.update(gallery_params)
redirect_to @gallery, status: :see_other
end
private
def gallery_params
params.require(:gallery).permit(images: [:ordinal])
end
View
<%= table_with(collection: gallery.images) do |row| %>
<% row.ordinal %>
<% row.text :name %>
<% end %>
<%= table_orderable_with(collection:, url: @gallery, scope: "gallery[image_attributes]") %>