zorab47 / active_admin-sortable_tree

Show ActiveAdmin index as a nested tree with drag'n'drop
MIT License
163 stars 127 forks source link

Feature Request: Selectively do not update the position field in "sort" action #96

Open awh-tokyo opened 2 years ago

awh-tokyo commented 2 years ago

My use case is that I would like a tree structure, but to have each level always sorted by name. I'd like to have the tree editor still work for easily setting parent/child relationships.

Currently I have to override the "sort" controller action so that it does not update the "position" field (which I have set to 'name'), or else all my objects get their name changed to numbers:

  # Override the one provided by ActiveAdminSortable, since we want it to ignore updates to the sort order
  collection_action :sort, :method => :post do
    resource_name = ActiveAdmin::SortableTree::Compatibility.normalized_resource_name(active_admin_config.resource_name)

    records = []
    params[resource_name].each_pair do |resource, parent_resource|
      parent_resource = resource_class.find(parent_resource) rescue nil
      records << [resource_class.find(resource), parent_resource]
    end

    errors = []
    ActiveRecord::Base.transaction do
      records.each_with_index do |(record, parent_record), position|
        # record.send "#{options[:sorting_attribute]}=", position
        if options[:tree]
          record.send "parent=", parent_record
        end
        errors << {record.id => record.errors} if !record.save
      end
    end
    if errors.empty?
      head 200
    else
      render json: errors, status: 422
    end
  end

Could we have a config option that allows us to disable the record.send "#{options[:sorting_attribute]}=", position ?

zorab47 commented 2 years ago

Thanks for posting the feature request!

How would the sorting be persisted? Could your model have a virtual no-op setter for :sorting_attribute?

class NamedTreeNode
  def no_op_sorting_attribute=(*)
    # do nothing
  end

  def parent=(record)
    # handle setting parent record
  end
end

Note: This assumes I fully recall how this library works.

awh-tokyo commented 10 months ago

I'm revisiting this because I thought about it while trying to clean up some code. The problem with your suggestion is that the :sorting_attribute is used as the sort order in index_as_sortable.rb:

          ol do
            item.send(options[:children_method]).order(options[:sorting_attribute]).each do |c|
              build_nested_item(c)
            end
          end if tree?

Setting the sorting_attribute to no_op_sorting_attribute causes the SQL generated by ActiveRecord to sort by a nonexistent column.