2

I'm using acts_as_list v0.9.17 this way:

class ListItem < ActiveRecord::Base
  acts_as_list scope: [:column1_id, :column2_id], :add_new_at => :bottom
end

When a new (scoped) @list_item is created, say the one where column1_id is 1, column2_id is 11 and column3_id is 37, the database looks as follows, as expected:

id  | position | column1_id | column2_id | column3_id
--- | -------- | ---------- | ---------- | ----------
750 | 1        | 1          | 11         | 89
751 | 2        | 1          | 11         | 56
752 | 3        | 1          | 11         | 105
753 | 4        | 1          | 11         | 25
754 | 5        | 1          | 11         | 37

However, when a @list_item is destroyed, say the one where column1_id is 1, column2_id is 11 and column3_id is 56 (record id 751), then the database looks as follows:

id  | position | column1_id | column2_id | column3_id
--- | -------- | ---------- | ---------- | ----------
750 | 1        | 1          | 11         | 89
752 | 3        | 1          | 11         | 105
753 | 4        | 1          | 11         | 25
754 | 5        | 1          | 11         | 37

That means there is a gap for position 2.

How to prevent or adjust the gap? That is, how to handle reordering of list items when a list item is destroyed?


Note: I know there are methods that change position and reorder list but I don't know whether and how to use them to solve the issue (maybe using someway remove_from_list).

1 Answer 1

2

As you say you need to use the method you provided, and you can either do it in your controller or the model itself. If you're the kind of guy who likes callbacks, then:

class ListItem < ActiveRecord::Base
  acts_as_list scope: [:column1_id, :column2_id], :add_new_at => :bottom
  before_destroy { |record| record.remove_from_list }

  ....
end

Some people don't like handling logic like that as a callback, so you can also add it straight into your controller:

class ListItemsController < Wherever
  ....
  ....

  def destroy
    @list_item.remove_from_list
    @list_item.delete

    ....
  end
end

Personally I'd add it into the model but they both do the same thing.

If you need to try and fix a list that has a missing record in it, say you have LineItems with an ID and position of 0-4 and 6-9, missing position 5. You can make a dirtyish fix in console with:

LineItem.where('position >= ?', 5).each { |line_item| line_item.update_attributes(position: line_item.position - 1) }

This will find all LineItems with a position over 4, and decrement each of them by one, leaving you with a correctly ordered list from 0-8.

8
  • The destroy callback is added for you: github.com/swanandp/acts_as_list/blob/… so no need to do it manually. Per github.com/swanandp/acts_as_list/issues/347 I think the OP has misconfigured something but we need more information. Commented Apr 8, 2019 at 0:28
  • I was wrong in showing column data and I updated the question. At this time I am solving the issue by using the before_destroy { |record| record.remove_from_list } callback inside the model but, since ActsAsList has one itself as @Brendon Muir pointed out, probably I should use it. Maybe I misconfigured something. Let me know if you need further info.
    – Backo
    Commented Apr 8, 2019 at 9:21
  • UPDATE - I (subtly) misconfigured the :scope option. Now all works without the use of the before_destroy callback. Thanks anyway.
    – Backo
    Commented Apr 8, 2019 at 10:20
  • Thanks for taking the time to update as I was about to spend some more time on this :)
    – Mark
    Commented Apr 8, 2019 at 15:10
  • 1
    @Backo, you should create an answer that shows your solution to the problem and accept that as the answer if this answer isn't the correct solution. Commented Apr 8, 2019 at 20:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.