acts_as_nested_set and nested display

52 views
Skip to first unread message

Zakk

unread,
Apr 12, 2007, 4:08:40 AM4/12/07
to ActiveScaffold : Ruby on Rails plugin
A few (quick?) questions.

I have a model that's set as acts_as_nested_set. I want to try to
display/manage this model in a sane way. For the typical nesting
depth of my application, I think nested activescaffold tables would do
just fine. Running into a a few snags implementing this.

My biggest issue is displaying the tables. Initially I'm used a
conditions_for_collection callback along with a record action link
that just calls the list action. The condtions callback looks to see
if there is an 'id' param set and returns an appropriate condition. So
if there's no id set it selects all the root nodes. If an id is set,
it selects all the nodes that have their parent_id set to the param
id. The action link displays inline and :after. This actually works
fairly well, except for one issue. There's no way to close the
'nested' table, since it's not being rendered with the active scaffold
nested capabilities.

Is there anyway to get the nested capabilities of active scaffold to
display these types of tables? Or at the very least an easy way for me
to display the little 'X' to close the inline table just like the
built-in nested table?


The other minor issue:

I setup a record action link that creates a new child of the current
record. I did this by overriding the 'create' controller method and
doing the correct add_child and save calls. I'm still trying to figure
out what to render/return from this function. Ideally I'd like it to
'open' the nested table for the parent of the newly created child, but
I'd settle for a notification that just said 'child created'. This may
be my inexperience with rails in general showing, but is there a way
to just flash the info message in active scaffold?

I realize this is quite a weird hackery of activescaffold; but I never
got anywhere by doing normal things ;)

Thanks for any assistance

Lance Ivy

unread,
Apr 12, 2007, 1:33:17 PM4/12/07
to actives...@googlegroups.com
The box used for nested scaffolds (and Update and Show) is wrapped around the response from those action link to adapt the response for inline display in the table. Thing is, the inline adapter should be standard fare, unless your record action link is ':position => false'. So I'm not sure why you don't see it.

Could you paste the configuration where you define these links?

Zakk

unread,
Apr 12, 2007, 5:09:57 PM4/12/07
to ActiveScaffold : Ruby on Rails plugin
Ah ha! I figured it out. The 'close' button is there, but the table
I'm displaying inline overlaps it and hides it

Here's how I'm setting it up:

config.action_links.add 'list', :type => :record, :inline =>
true, :position
=> :after

On Apr 12, 1:33 pm, "Lance Ivy" <l...@cainlevy.net> wrote:
> The box used for nested scaffolds (and Update and Show) is wrapped around
> the response from those action link to adapt the response for inline display
> in the table. Thing is, the inline adapter should be standard fare, unless
> your record action link is ':position => false'. So I'm not sure why you
> don't see it.
>
> Could you paste the configuration where you define these links?
>

Zakk

unread,
Apr 15, 2007, 7:16:29 AM4/15/07
to ActiveScaffold : Ruby on Rails plugin
In case anyone else wants to do something like this; I think I've
gotten things mostly working. Turns out a completely different
approach was best.

Here's the code:

create_table "devicetypes" do |t|
t.column :created_on, :timestamp
t.column :updated_on, :timestamp
t.column :description, :string
t.column :parent_id, :integer
t.column :lft, :integer
t.column :rgt, :integer
end


class Nestedset < ActiveRecord::Base
acts_as_nested_set
has_many :children, :class_name => 'Devicetype', :foreign_key =>
"parent_id"
belongs_to :parent, :class_name => 'Devicetype', :foreign_key =>
"parent_id"
end


class NestedsetController < ApplicationController
active_scaffold :nestedset do |config|
columns[:description].set_link('nested', :parameters =>
{:associations => :children})
config.list.columns.exclude :children,:parent, :lft, :rgt
config.update.columns.exclude :lft, :rgt, :children,:parent
config.create.columns.exclude :lft, :rgt, :children,:parent
end


def after_create_save(record)
return if !@record.parent
@record.parent.add_child(@record)
end

def conditions_for_collection
return ['parent_id is NULL'] if !params.has_key?(:nested)
end
end

Basically you create has_many/belongs_to associations to 'trick'
active scaffold into seeing the acts_as_nested_set in such a way that
it triggers nested tables.

Combined with the conditions_for_collection method you get an initial
display of just the nodes that have no parents ("root" nodes). When
you click on any of the descriptions you get a nested scaffold that
contains only children of that node. And it cascades deeper in the
same manner. The 'Create New' link on each table creates children of
the proper node with help from the after_create_save.

The only bug I've seen is that sometimes after you create a child
display it in the wrong table. This is because the HTML ids are only
unique on a controller basis. There's multiple tables with the same
controller name on the page, so sometimes the javascript finds the
wrong table. The record is created with the correct parent, it'll just
display wrong until you refresh the page. Fixing this would require
some changes in the ActiveScaffold code, which I may tackle a bit
later.

If anyone sees an obvious way to improve on this, please let me know.


Lance Ivy

unread,
Apr 15, 2007, 12:19:12 PM4/15/07
to actives...@googlegroups.com
Great work!

Zakk

unread,
Apr 15, 2007, 3:32:16 PM4/15/07
to ActiveScaffold : Ruby on Rails plugin
Change all the instances of 'Devicetype' to 'Nestedset'. Didn't change
all the names to the example name. That's what I get for staying up so
late.

On Apr 15, 12:19 pm, "Lance Ivy" <l...@cainlevy.net> wrote:
> Great work!
>

> > return if !...@record.parent

Jeff

unread,
May 7, 2007, 12:56:01 AM5/7/07
to ActiveScaffold : Ruby on Rails plugin
Zakk,

Tried your code and I get the nested tables displayed properly, but
adding a child node has very strange behavior. What happens is no
matter how deep into the tree I am, the child node I add is inserted
into the database with no parent, putting it at the root. For reasons
I don't know, an update query is then done on the original parent
node, making it a child of the record I justed inserted. I don't know
where this query is coming from.

So if it looks like this:

- "Node"
---- (I add "Subnode" here)

When I refresh the page, here's what I get:

- "Subnode"
--- "Node"

Any idea what could be causing this?

> > > active scaffold into seeing theacts_as_nested_setin such a way that

Zakk

unread,
May 7, 2007, 7:22:14 AM5/7/07
to ActiveScaffold : Ruby on Rails plugin
The 'extra' query is likely coming from inside active scaffold where
it forces a save. I noticed something changed and things sorta broke
somewhere along the line. I changed up what I'm doing; specifically I
moved the child adding into the model using and after_create callback.

my callback looks like this:

def setchild
if self[:parent_id].nil?
return true
end
self.save
self.move_to_child_of self.parent
return true
end

Note: I'm using the better_nested_set plugin which is where the
move_to_child_of method comes from. If you aren't you just add the
child normally. It also seems it might be smarter to move this to an
after_save callback; but I can't remember if I tried that and it
didn't work or not.

The self[:parent_id] thing is a bit weird. If you just do
self.parent.nil? and it's true, active scaffold breaks when it tries
to force the object and all it's associations to fail. So I have to
avoid a direct reference to self.parent

Guys: the forced saving of a record AND all it's loaded associations
(and their associations etc etc etc) is generating TONS of completely
unecessary SQL UPDATE statements (and breaks in some cases as seen
above with the self.parent case). Normally it's ok if you never touch
the associations, as they aren't loaded. But I've got some code that
loads quite a few associations in order to properly handle some
operations; and they all get updated by active scaffold. I can see
this being the source of some performance issues in the future.

Lance Ivy

unread,
May 7, 2007, 11:29:23 AM5/7/07
to actives...@googlegroups.com
We've optimized the saving a bit in trunk so that it only saves records/associations from the form.

Jeff

unread,
May 7, 2007, 4:32:43 PM5/7/07
to ActiveScaffold : Ruby on Rails plugin
I switched to the callback in the model and seem to be getting the
same behavior. The problem is the model doesn't ever seem to have a
parent id to begin with, so the move_to_child_of part never executes
(I'm using better nested set as well). I find it bizarre that the
update on the parent row acquires the id of the recently created child
row, and then uses it as its parent (putting the original parent
beneath what I just created).

I spent 4 or 5 hours on this last night combing through code, I know
it's going to end up being something really obvious because something
Is happening, it's just backwards.

Here's the model:

class Category < ActiveRecord::Base
has_many :children, :class_name => 'Category', :foreign_key =>
'parent_id'
belongs_to :parent, :class_name => 'Category', :foreign_key =>
'parent_id'
has_many :articles

acts_as_nested_set
validates_presence_of :title

after_create :setchild

def setchild
if self[:parent_id].nil?
return true
end
self.save
self.move_to_child_of self.parent
return true
end

end

And controller:

class CategoryController < ApplicationController
layout 'admin'

active_scaffold :category do |config|
config.columns[:title].set_link('nested', :parameters =>


{:associations => :children})
config.list.columns.exclude :children, :parent, :lft, :rgt

config.create.columns = :title, :description
config.update.columns = :title, :description
end

def conditions_for_collection
return ['parent_id IS NULL'] if !params.has_key?(:nested)
end
end

Zakk

unread,
May 8, 2007, 7:01:09 AM5/8/07
to ActiveScaffold : Ruby on Rails plugin
I should update before I complain, eh!?


Jeff: your problem sounds familiar, let me look around my code and see
how I dealt with that.


On May 7, 11:29 am, "Lance Ivy" <l...@cainlevy.net> wrote:
> We've optimized the saving a bit in trunk so that it only saves
> records/associations from the form.
>

Tys von Gaza

unread,
May 18, 2007, 7:55:35 PM5/18/07
to ActiveScaffold : Ruby on Rails plugin
Any more word on getting this working? We're running into the same
problems. It seems like ActiveScaffold isn't setting the child's
parent or something like that. Will dig deeper into it next week.

Cheers,
Tys

Reply all
Reply to author
Forward
0 new messages