SitePoint Sponsor

User Tag List

Results 1 to 6 of 6

Thread: Counting

  1. #1
    SitePoint Wizard rctneil's Avatar
    Join Date
    Jun 2005
    Posts
    1,891
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question Counting

    Hey,

    Pretty much a follow up to my previous thread on here but thought it warranted it's own topic.

    Background:

    I have 3 models:

    Code:
    Collections
      has_many collections as children
      belongs_to collection as parent
    
    
    Albums
      belongs_to collection
      has_many photos
    
    
    Photos
      belongs_to album


    Basically I want to write an instance method for a collection to return the total number of photos of ALL children albums including all those albums in children collections of the calling collection.

    So for example:

    Code:
    Collection 1
      Collection 2
        Album 1 - 5 photos
        Album 2 - 6 photos
      Collection 3
        Album 3 - 10 photos
    Calling photo_count on collection 1 would return 21 and calling it on collection 2 would return 11

    I have tried to write it as follows but it's not quite right, I realise I need to use a try method somewhere but i'm just not sure how to finish it off.

    Code Ruby:
      def photo_count
        count = 0
        albums.each do |album|
          count += album.photo_count
        end
      end

    Could anyone give me a hand here?

    Neil

  2. #2
    padawan silver trophybronze trophy markbrown4's Avatar
    Join Date
    Jul 2006
    Location
    Victoria, Australia
    Posts
    4,108
    Mentioned
    28 Post(s)
    Tagged
    2 Thread(s)
    Hi Neil,

    I'd be looking for gems to solve this, checkout ancestry which will let you do albums.descendants.count
    https://github.com/stefankroes/ancestry

    But, you can probably do something like this if you do want to code it yourself.
    http://www.dzone.com/snippets/find-a...ren-actsastree

  3. #3
    SitePoint Wizard rctneil's Avatar
    Join Date
    Jun 2005
    Posts
    1,891
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The tree gems would work fine but only saw those after I had started building it manually which actually wasn't that difficult in the first place. It's not actually the model that is being the tree I want to query, It't the items at the end of the branches I want information from.

    In my app, the collections act as a tree and the albums just sit at the ends, each albums just has a parent collection id to show what collection it belongs to. Please see the collection/album hierarchy I posted above, sorry, it may have seemed a bit confusing but I need to be able to find out how many photos are in every collection but just unsure how to put everything together to get the right results.

    Neil

  4. #4
    padawan silver trophybronze trophy markbrown4's Avatar
    Join Date
    Jul 2006
    Location
    Victoria, Australia
    Posts
    4,108
    Mentioned
    28 Post(s)
    Tagged
    2 Thread(s)
    It does seem like one of your models isn't necessary.
    I would have gone with something like this and the ancestry gem.
    Code:
    Album 1
      Album 2
        Album 3 - 5 photos
        Album 4 - 6 photos
      Album 5
        Album 6 - 10 photos
    I'd suggest looking at those gems again and implementing one of the their searching algorithms for getting all the descendants.
    It's the recursive tree part that is tripping you up, once you have that it's easy.
    Code Ruby:
    Class Collection < ActiveRecord::Base
     
      def photo_count
        albums = descendants.collect! { |x| x.albums }
        albums.collect! { |x| x.photos }.length
      end
     
    end
    Or if you can make collections have many photos through albums you could just use
    descendants.collect! { |x| x.photos }.length

  5. #5
    SitePoint Member
    Join Date
    Aug 2012
    Posts
    1
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This code is not far off:

    Code Ruby:
    def photo_count
      count = 0
      albums.each do |album|
        count += album.photo_count
      end
    end

    If you return the count at the end it should work, i.e:

    Code Ruby:
    def photo_count
      count = 0
      albums.each do |album|
        count += album.photo_count
      end
      count
    end

    This is a common programming pattern, and there's a much shorter way of writing it:

    Code Ruby:
    def photo_count
      albums.inject(0) { |sum, album| sum + album.photo_count }
    end

    A bit like using "each" instead of writing for loops by hand, much easier!

    The ultra concise version would be this:

    Code Ruby:
    def photo_count
      albums.map(&:photo_count).inject(0, &:+)
    end

    Whether that's easier or harder to understand than the original depends on what you're used to

    Cheers,
    Tim

  6. #6
    SitePoint Addict
    Join Date
    Feb 2007
    Posts
    270
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just curious: Have you looked into using :counter_cache for doing this?


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •