swanandp/acts_as_list — Issue #21: increment_positions_on_lower_items called twice on insert_at with new item
Author: demery
Created: 2011-11-14 17:49:28+00:00
State: open

I found unexpected behavior when I call `insert_at(position)` on a new item (as is shown in the `test_list.rb` in the gem). If I insert a newly created (and not yet saved object), `increment_positions_on_lower_items` gets called twice, so that given positions `[1,2]`, `new_object.insert_at(2)` results in positions `[1,2,4]`.

See the following:

```ruby
## GET THE PARENT
ruby-1.9.2-p290 :030 > shoot_list = ShootList.first
ShootList Load (0.6ms) SELECT "shoot_lists".* FROM "shoot_lists" LIMIT 1
=> #

### TWO ORDERED CHILDREN IN THE LIST
ruby-1.9.2-p290 :031 > shoot_list.shot_sequences.map(&:position)
ShotSequence Load (0.7ms) SELECT "shot_sequences".* FROM "shot_sequences" WHERE "shot_sequences"."shoot_list_id" = 1 ORDER BY position
=> [1, 2]

## CREATE A NEW CHILD AND INSERT IT
ruby-1.9.2-p290 :032 > shot_sequence = ShotSequence.new(:subject => "elephant", :shoot_list => shoot_list)
=> #
ruby-1.9.2-p290 :033 > shot_sequence.insert_at(2)
SQL (2.2ms) UPDATE "shot_sequences" SET position = (position + 1) WHERE ("shot_sequences"."shoot_list_id" = 1 AND position >= 2)
(0.1ms) BEGIN
SQL (0.4ms) UPDATE "shot_sequences" SET position = (position + 1) WHERE ("shot_sequences"."shoot_list_id" = 1 AND position >= 2)
SQL (0.7ms) INSERT INTO "shot_sequences" ("created_at", "operator_instructions", "position", "rotation_degrees", "shoot_list_id", "subject", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["created_at", Mon, 14 Nov 2011 12:34:05 EST -05:00], ["operator_instructions", nil], ["position", 2], ["rotation_degrees", 0], ["shoot_list_id", 1], ["subject", "elephant"], ["updated_at", Mon, 14 Nov 2011 12:34:05 EST -05:00]]
(0.4ms) COMMIT
=> true

### RELOAD THE PARENT AND LIST THE CHILDREN
ruby-1.9.2-p290 :035 > shoot_list = ShootList.first
ShootList Load (0.6ms) SELECT "shoot_lists".* FROM "shoot_lists" LIMIT 1
=> #
ruby-1.9.2-p290 :036 > shoot_list.shot_sequences.map(&:position)
ShotSequence Load (0.8ms) SELECT "shot_sequences".* FROM "shot_sequences" WHERE "shot_sequences"."shoot_list_id" = 1 ORDER BY position
=> [1, 2, 4]
ruby-1.9.2-p290 :037 >
```
Note that two update calls are made to do the position increment. I stuck a backtrace printout in `increment_positions_on_lower_items(position)` and found the first call was made on insert and the second when the `before_create` callback is made.

Creating the item, and then inserting it in the correct position gets the desired result.