Forum: Ruby on Rails one-to-many and acts_as_tree troubles

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
7b8c70596a9a78dfd8abe8e400f1bda5?d=identicon&s=25 zeke () (spacesquirrel)
on 2007-07-13 04:23
ok. so i’ve got two models, Photo and Place:

  class Photo < ActiveRecord::Base
     belongs_to :place, :counter_cache => true

  class Place < ActiveRecord::Base

     acts_as_tree :order => "name"
     has_many :photo

the places database contains specific locations, cities, and states. the
specific locations connect to cities by parent_id and in turn cities
connect to states by parent_id.

each Photo belongs to a Place, referencing to a place_id in the photos
table.

for some reason, i can’t get the one-to-many relationship to work out.
when i put

<%= place.photos.size %>

in a view, i get a NoMethodError saying that ‘photos’ is an undefined
method of the Place model.

any ideas?
E868385dea4df1e5d4a75befd5adc38e?d=identicon&s=25 fat (Guest)
on 2007-07-13 05:20
(Received via mailing list)
On Jul 13, 9:23 am, Zeke Runyon <rails-mailing-l...@andreas-s.net>
wrote:
> the places database contains specific locations, cities, and states. the
>
> in a view, i get a NoMethodError saying that 'photos' is an undefined
> method of the Place model.
>
> any ideas?
>
> --
> Posted viahttp://www.ruby-forum.com/.

Try to change :
    from
         class Place < ActiveRecord::Base
         acts_as_tree :order => "name"
         has_many :photo

   to
         class Place < ActiveRecord::Base
         acts_as_tree :order => "name"
         has_many :photos  #<------
may be help you
p.s. sorry for my english
7b8c70596a9a78dfd8abe8e400f1bda5?d=identicon&s=25 zeke () (spacesquirrel)
on 2007-07-13 17:53
ah, that did it! thanks!!

now i've got a new problem. so, with my hierarchical places structure
i'd like to be able to count (and allow to be counter_cache-d) the
number of photos associated with any descendant of a particular place.

for example, say i've got a photo that references the place "central
park" which in turn references to "manhattan" which references to "new
york" in the Places tree. i'd like to be able to call this:

     Place.find_by_name("new york").photos.size

and get the number of photos taken anywhere in manhattan and new york
combined... i thought this could be accomplished by adding a :conditions
to the has_many statement in the Place model:

     class Place < ActiveRecord::Base

          acts_as_tree :order => "name"
          has_many :photos, :conditions => include_descendants

          def descendants
               (self.children.each { |child| child.descendants }.flatten
+ self)
          end

          def include_descendants
               conditions = "place_id = #{self.id}"
               self.descendants.each do |place|
                    conditions << " or place_id = #{place.id}"
               end
               return conditions
          end

     end

but i get a NameError, saying that include_descendents is undefined. any
suggestions on how to get this to work?

thanks in advance,
z.
7b8c70596a9a78dfd8abe8e400f1bda5?d=identicon&s=25 zeke () (spacesquirrel)
on 2007-07-13 20:57
actually, the recursive descendants method doesn't really work. here's a
replacement.

     def descendants
          descendants = []
          self.children.each do |child|
               descendants << child
               if child.children
                    child.children.each do |grandchild|
                         descendants << grandchild
                    end
               end
          end
          return descendants.flatten
     end

i'm able to successfully use this function elsewhere, but i still can't
get the :conditions of the has_many to call include_descendents...

z.
7b8c70596a9a78dfd8abe8e400f1bda5?d=identicon&s=25 zeke () (spacesquirrel)
on 2007-07-13 20:58
> i'm able to successfully use this function elsewhere, but i still can't
> get the :conditions of the has_many to call include_descendents...

ack! include_descendants, rather.

z.
E60b2dc57668b5662ce3f07781e41710?d=identicon&s=25 Matthew Rudy Jacobs (matthewrudy)
on 2007-07-14 17:07
>      class Place < ActiveRecord::Base
>
>           acts_as_tree :order => "name"
>           has_many :photos, :conditions => include_descendants
>
>           def descendants
>                (self.children.each { |child| child.descendants }.flatten
> + self)
>           end
>
>           def include_descendants
>                conditions = "place_id = #{self.id}"
>                self.descendants.each do |place|
>                     conditions << " or place_id = #{place.id}"
>                end
>                return conditions
>           end
>
>      end

the problem you have is that when you write

class Klass
    has_many :photos, :conditions => include_descendants
end

you're actually writing
class Klass
    self.has_many(:photos, :conditions => include_descendants)
end

ie. the method is being called as a class method on Klass,
and, as such, the "include_descendants" is being evaluated when you
declare the has_many.

so, the following would evaluate like this

class Klass
    def self.include_descendants
        "this string gets evaluated at class load time"
    end
    has_many :photos, :conditions => include_descendants
end

this would actually define

has_many :photos, :conditions => "this string gets evaluated at class
load time"

which is plainly not what you want.

(if i wasnt about to go play tennis, I'd have a go at writing the
recursive relation in SQL for you, so we can make it work proper)
7b8c70596a9a78dfd8abe8e400f1bda5?d=identicon&s=25 zeke () (spacesquirrel)
on 2007-07-14 19:44
> has_many :photos, :conditions => "this string gets evaluated at class
> load time"
>
> which is plainly not what you want.

ah! i see where this is going now.

> (if i wasnt about to go play tennis, I'd have a go at writing the
> recursive relation in SQL for you, so we can make it work proper)

eek! maybe i'm going down the wrong road for storing this information.
perhaps i should migrate to acts_as_nested_set or dotted ids (as
suggested at
http://blog.rapidred.com/articles/2006/06/08/ruby-...) so
i could find all descendants with one sql query.

maybe then i could set up the has_many :conditions more easily to work
with counter_cache? after all, i could just maintain a photos_count
column of my places table manually, updating it whenever a place is
added to or deleted from the database...

thoughts?

z.
This topic is locked and can not be replied to.