[Betternestedset-talk] before_update problem

Matthias Heigl mhe_mailing at gmx.de
Sun Dec 31 09:19:23 EST 2006


Hi Krishna,

after a bit sleep i made a clean test, maybe my other code could cause this problem.

So i set up a clean acts_as_nested_set.

My migration

- - - - -
class CreateItems < ActiveRecord::Migration
  def self.up
    create_table :items do |t|
      # acts_as_nested_set colums
      t.column :parent_id, :integer
      t.column :lft, :integer
      t.column :rgt, :integer

      # common attributes
      t.column :name, :string
    end
  end
...
- - - - -

my model item.rb

- - - - -
class Item < ActiveRecord::Base

  acts_as_nested_set

  before_update :update_fields 
  before_create :update_create
  private
  
  def update_fields
    logger.info "--- item: before update ---"
    logger.info "#{self.name} - #{self}"
  end  
  
  def update_create
    logger.info "--- item: before create ---"
    logger.info "#{self.name} - #{self}"
  end

end
- - - - -

created a clean scaffold on this and added in items_controller.rb

- - - - -
...
  def add
    @item = Item.new
    @item.parent_id = params[:id]
    render :action => 'new'
  end

  def create
    @item = Item.new(params[:item])
    if @item.parent_id.to_i > 0
      parent = Item.find(@item.parent_id)
      if @item.save
        parent.add_child(@item)
        flash[:notice] = 'Item was successfully added.'
        redirect_to :action => 'list'
      end
    else
      if @item.save
        flash[:notice] = 'Item was successfully created.'
        redirect_to :action => 'list'
      else
        render :action => 'new'
      end
    end
  end
...
- - - - -
remark: i know it's ugly but for a quick test it will be ok.

_form.rhtml added

- - - - -
Parent: <%= text_field 'item', 'parent_id' %>
- - - - -

here goes my steps an log:

- - - - -
1. add "new item"

Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:43:50) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"new item", "lft"=>"", "rgt"=>"", "parent_id"=>""}}
  Item Columns (0.010000)   SHOW FIELDS FROM items
  SQL (0.000000)   BEGIN
--- item: before create ---
new item - #<Item:0x574b760>
  SQL (0.000000)   INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('new item', NULL, NULL, NULL, NULL)
  SQL (0.000000)   COMMIT
Redirected to http://localhost:3000/items/list
Completed in 0.04000 (25 reqs/sec) | DB: 0.01000 (25%) | 302 Found [http://localhost/items/create]


2. edit "new item"

Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:45:39) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"8", "controller"=>"items", "item"=>{"name"=>"new item - edit", "lft"=>"", "rgt"=>"", "parent_id"=>""}}
  Item Columns (0.000000)   SHOW FIELDS FROM items
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 8) 
  SQL (0.000000)   BEGIN
--- item: before update ---
new item - edit - #<Item:0x55cc13c>
  Item Update (0.000000)   UPDATE items SET `rgt` = NULL, `type` = NULL, `lft` = NULL, `parent_id` = NULL, `name` = 'new item - edit' WHERE id = 8
  SQL (0.000000)   COMMIT
Redirected to http://localhost:3000/items/show/8
Completed in 0.05000 (20 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/update/8]


3. add_child "child item" to "new item - edit"

Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:46:35) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"child item", "lft"=>"", "rgt"=>"", "parent_id"=>"8"}}
  Item Columns (0.000000)   SHOW FIELDS FROM items
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 8) 
  SQL (0.000000)   BEGIN
--- item: before create ---
child item - #<Item:0x56df8a8>
  SQL (0.000000)   INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('child item', NULL, NULL, 8, NULL)
  SQL (0.000000)   COMMIT
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 8) 
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 9) 
  SQL (0.000000)   BEGIN
--- item: before update ---
new item - edit - #<Item:0x56d5218>
  Item Update (0.000000)   UPDATE items SET `rgt` = 4, `type` = NULL, `lft` = 1, `parent_id` = NULL, `name` = 'new item - edit' WHERE id = 8
  SQL (0.000000)   COMMIT
  SQL (0.000000)   BEGIN
--- item: before update ---
child item - #<Item:0x56df8a8>
  Item Update (0.000000)   UPDATE items SET `rgt` = 3, `type` = NULL, `lft` = 2, `parent_id` = 8, `name` = 'child item' WHERE id = 9
  SQL (0.000000)   COMMIT
Redirected to http://localhost:3000/items/list
Completed in 0.07000 (14 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/create]


4. edit "child item"

Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:47:39) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"9", "controller"=>"items", "item"=>{"name"=>"child item - edit", "lft"=>"2", "rgt"=>"3", "parent_id"=>"8"}}
  Item Columns (0.010000)   SHOW FIELDS FROM items
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 9) 
  SQL (0.000000)   BEGIN
--- item: before update ---
child item - edit - #<Item:0x5550834>
  Item Update (0.000000)   UPDATE items SET `rgt` = 3, `type` = NULL, `lft` = 2, `parent_id` = 8, `name` = 'child item - edit' WHERE id = 9
  SQL (0.000000)   COMMIT
Redirected to http://localhost:3000/items/show/9
Completed in 0.04000 (25 reqs/sec) | DB: 0.01000 (25%) | 302 Found [http://localhost/items/update/9]

- - - - -

After that i added betternestedset to vendor/plugins. Because of "Unauthorized assignment to parent_id: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." i hardcoded the parent id in the controller. For this test it seems ok to me. 

- - - - -
...
  def reply
    @item = Item.new
    #@item.parent_id = params[:id]
    render :action => 'new'
  end

  def create
    @item = Item.new(params[:item])
    if true
      parent = Item.find(1)
      if @item.save
        @item.move_to_child_of parent
        flash[:notice] = 'Item was successfully added.'
        redirect_to :action => 'list'
      end
    else
      if @item.save
        flash[:notice] = 'Item was successfully created.'
        redirect_to :action => 'list'
      else
        render :action => 'new'
      end
    end
  end
...
- - - - -

here goes my steps and log


1. add "new item"

Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:52:41) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"new item", "lft"=>"", "rgt"=>"", "parent_id"=>""}}
  Item Columns (0.000000)   SHOW FIELDS FROM items
  SQL (0.000000)   BEGIN
--- item: before create ---
new item - #<Item:0x56ce7c4>
  SQL (0.000000)   SELECT max(rgt) AS max_rgt FROM items WHERE (1 = 1) 
  SQL (0.000000)   INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('new item', 1, NULL, NULL, 2)
  SQL (0.000000)   COMMIT
Redirected to http://localhost:3000/items/list
Completed in 0.04000 (25 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/create]


2. edit "new item"

Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:53:13) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"1", "controller"=>"items", "item"=>{"name"=>"new item - edit", "lft"=>"1", "rgt"=>"2", "parent_id"=>""}}
  Item Columns (0.000000)   SHOW FIELDS FROM items
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 1) 
  SQL (0.000000)   BEGIN
  Item Update (0.000000)   UPDATE items SET `type` = NULL, `parent_id` = NULL, `name` = 'new item - edit' WHERE id = 1
  SQL (0.000000)   COMMIT
Redirected to http://localhost:3000/items/show/1
Completed in 0.09000 (11 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/update/1]


3. add "child item" and move_to_child_of "new item - edit"

Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:55:21) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"child item", "lft"=>"", "rgt"=>"", "parent_id"=>""}}
  Item Columns (0.000000)   SHOW FIELDS FROM items
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 1) 
  SQL (0.000000)   BEGIN
--- item: before create ---
child item - #<Item:0x55b83f8>
  SQL (0.000000)   SELECT max(rgt) AS max_rgt FROM items WHERE (1 = 1) 
  SQL (0.000000)   INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('child item', 3, NULL, NULL, 4)
  SQL (0.010000)   COMMIT
  SQL (0.000000)   BEGIN
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 2) 
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 1) 
  Item Update (0.010000)   UPDATE items SET lft = CASE WHEN lft BETWEEN 2 AND 2 THEN lft + 2 WHEN lft BETWEEN 3 AND 4 THEN lft + -1 ELSE lft END, rgt = CASE WHEN rgt BETWEEN 2 AND 2 THEN rgt + 2 WHEN rgt BETWEEN 3 AND 4 THEN rgt + -1 ELSE rgt END, parent_id = CASE WHEN id = 2 THEN 1 ELSE parent_id END WHERE (1 = 1) 
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 2) 
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 1) 
  SQL (0.010000)   COMMIT
Redirected to http://localhost:3000/items/list
Completed in 0.07000 (14 reqs/sec) | DB: 0.03000 (42%) | 302 Found [http://localhost/items/create]


4. edit "child item"

Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:56:08) [POST]
  Session ID: 9e719642e8a39389a8386344d6c4fc96
  Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"2", "controller"=>"items", "item"=>{"name"=>"child item - edit", "lft"=>"2", "rgt"=>"3", "parent_id"=>"1"}}
  Item Columns (0.000000)   SHOW FIELDS FROM items
  Item Load (0.000000)   SELECT * FROM items WHERE (items.id = 2) 
  SQL (0.000000)   BEGIN
  Item Update (0.000000)   UPDATE items SET `type` = NULL, `parent_id` = 1, `name` = 'child item - edit' WHERE id = 2
  SQL (0.000000)   COMMIT
Redirected to http://localhost:3000/items/show/2
Completed in 0.04000 (25 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/update/2]

- - - - -

As you can see, after adding betternestedset no more before_update callback is executed.

I hope this is helpful.

And happy New Years Eve Everyone!

Cheers,

Matze

-------- Original-Nachricht --------
Datum: Sat, 30 Dec 2006 23:51:18 -0500
Von: "Krishna Dole" <dontfall at gmail.com>
An: betternestedset-talk at rubyforge.org
Betreff: Re: [Betternestedset-talk] before_update problem

> Hi Matze,
> 
> Thanks for letting us know about this. I'll certainly look into it,
> but it might not be for a few days.
> 
> Krishna
> 
> On 12/30/06, Matthias Heigl <mhe_mailing at gmx.de> wrote:
> > Hi List,
> >
> > first of all i introduce myself.
> >
> > I am a fairly ror-newbie, with 2 week experience on it. I'm developing a
> departent-management application with one STI-Table.
> >
> > Issue < ActiveRecord::Base
> > Project < Issue
> > Milestone < Project
> > Task < Milestone
> >
> > Because of the STI problem in acts_as_nested_set i found betternestedset
> and used it. Now i have a problem. It seems that before_update callback
> doesn't work anymore.
> >
> > First i wondered why my magic field updated_at didn't get updated when i
> edit any Project, Milestone or Task. Then for tests i added the following
> to my model issue.rb
> >
> > - - - - - -
> >   before_update :update_fields
> >   before_create :update_create
> >   private
> >
> >   def update_fields
> >     logger.info "--- issue: before update ---"
> >   end
> >
> >   def update_create
> >     logger.info "--- issue: before create ---"
> >   end
> > - - - - - -
> >
> > In my log only the before_create on create appears but never the
> before_update on updates.
> >
> > A quick test, im really not shure, with normal acts_as_nested_set and
> only on Issue, because of the STI problem, everything was ok.
> >
> > Another issue i recognized is that the before_create callback is
> executed three times with betternestedset/acts_as_nested_set. This could be a
> performance issue in certain circumstances.
> >
> > I hope there is a solution, because i need the before_update callback of
> some other reasons.
> >
> > Cheers,
> >
> > Matze
> > _______________________________________________
> > Betternestedset-talk mailing list
> > Betternestedset-talk at rubyforge.org
> > http://rubyforge.org/mailman/listinfo/betternestedset-talk
> >
> _______________________________________________
> Betternestedset-talk mailing list
> Betternestedset-talk at rubyforge.org
> http://rubyforge.org/mailman/listinfo/betternestedset-talk


More information about the Betternestedset-talk mailing list