SitePoint Sponsor

User Tag List

Results 1 to 19 of 19
  1. #1
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    how to handle "stacking order" of a collection

    I suppose this may be more of a database question, but what is the best way to handle this scenario.
    I have the following tables: articles, collections, articles_collections
    a collection contains many articles but I want to be able to order them. Would I simply add a "stacking_order" column to the articles table?
    Although, an article can belong to many collections and each would have different stacking orders.
    Any suggestions?

  2. #2
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It sounds like you want a join model between your Article and Collection. Without knowing more about your domain its hard to put a name to it, but lets say that model is called Foo. You'd have articles, collections and foos tables. The foos table will have an article_id, a collection_id and a stacking_order column. Your models would look a bit like this:

    Code:
    class Article < ActiveRecord::Base
      has_many :foos, :order => 'stacking_order ASC'
      has_many :collections, :through => :foo
    end
    
    class Collection < ActiveRecord::Base
      has_many :foos, :order => 'stacking_order'
      has_many :articles, :through => :foo
    end
    
    class Foo < ActiveRecord::Base
      belongs_to :article
      belongs_to :collection
    end
    Not tested, but hope that helps.

  3. #3
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Luke,
    Thanks for your help, my join table would be articles_collections. Why do you use has_many through instead of has_and_belongs_to_many?

  4. #4
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Because that way you can store extra information about the relationship, such as the stacking order. Take a look at this article:

    http://blog.hasmanythrough.com/artic...many-dance-off

  5. #5
    Non-Member
    Join Date
    Jul 2005
    Posts
    606
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    might be a good chance to use polymorphic associations

  6. #6
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi,
    I changed my has_and_belongs_to_many to use has_many through and now my tests are throwing mysql errors like "Cannot add or update a child row: a foreign key constraint fails:"
    Any idea on what I'll need to do to fix?

    When setting foreign keys what should set the "on delete" and "on update" handlers to CASCADE, SET_NULL, NO ACTION, RESTRICT

  7. #7
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Personally, I wouldn't bother with foreign key constraints in your database unless it has to be accessed by several different apps. Use your Rails models to set your constraints. Database constraints just make things a pain in the **** to test.

  8. #8
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok I'm totally confused, I removed the foreign keys and now i get "ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :compositions"

    Here's what I had working with the has_and_belongs_to_many:

    PHP Code:
       class Collection ActiveRecord::Base
           has_and_belongs_to_many 
    :articles
        belongs_to 
    :author
        
        def add
    (article)
            
    articles << article
        end

       
    class Author ActiveRecord::Base
           has_many 
    :articles
       
       
    class Article ActiveRecord::Base
           belongs_to 
    :author
           has_and_belongs_to_many 
    :collections 

    Which i have changed to :

    PHP Code:
        class Collection ActiveRecord::Base
            has_many 
    :articles, :through => :collection_items
         belongs_to 
    :author
         
         def add
    (article)
    #SHOULD I BE REFERRING TO collection_items instead of articles?
             
    articles << article
         end
     
        
    class Author ActiveRecord::Base
        has_many 
    :articles
        has_many 
    :collections
        
        
    class Article ActiveRecord::Base
            belongs_to 
    :author
            has_many 
    :collections, :through => :collection_items

    class CollectionItem ActiveRecord::Base
        belongs_to 
    :article
        belongs_to 
    :collection 

  9. #9
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Where is the compositions coming from?

  10. #10
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    sorry about that I cut and paste from another test.
    Could not find the association :collection_items

  11. #11
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    No ideas, this is driving me insane.
    I mean should what I'm doing here work?
    Would a collection have a reference to an articles array? or since I am going thru collection_items would I have to access something like my_collection.collection_items.articles?

    I have to say I thought habtm was confusing, but this tops it. I don't know if i'm being particularly dense, but i appreciate your help so far.

  12. #12
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, lets start over.

    Here are my models:
    PHP Code:
      class Article ActiveRecord::Base
          belongs_to 
    :author
          has_many 
    :collections, :through => :collection_items
      end
      
      
    class Author ActiveRecord::Base
          has_many 
    :articles
          has_many 
    :collections
      end
      
      
    class Collection ActiveRecord::Base
              has_many 
    :articles, :through => :collection_items
              belongs_to 
    :author
              
              def add
    (article)
                  
    articles << article
              end
              
              def remove
    (article)
                  if 
    articles.detect{|i== article}
                      
    articles.delete(article)
                  
    end
              end
      end
      
      
    class CollectionItem ActiveRecord::Base
          belongs_to 
    :article
          belongs_to 
    :collection
      end 
    Here are my fixtures:

    collection_items.yml
    PHP Code:
      item1:
        
    article_id1
        collection_id
    1
        stacking_order
    1
      item2
    :
        
    article_id2
        collection_id
    1
        stacking_order
    2
      item3
    :
        
    article_id1
        collection_id
    2
        stacking_order

    articles.yml
    PHP Code:
      article1:
        
    id1
        author_id
    1
        keywords
    web development
        body
    This is an article about web design and development with Ruby
      
      article2
    :
        
    id2
        author_id
    2
        keywords
    something
        body
    This is an article about something else 
    collections.yml
    PHP Code:
      collection1:
        
    id1
        author_id
    1
        name
    newsletter
      collection2
    :
        
    id2
        author_id
    1
        name
    webpage 
    And here's a test that fails...
    PHP Code:
        fixtures :collections, :articles, :collection_items 

          def test_how_many_articles
              result 
    Collection.find(1)
              
    assert_equal 2result.articles.length
          end 
    with this error:
    PHP Code:
      test_how_many_articles(TestCollection):
      
    ActiveRecord::HasManyThroughAssociationNotFoundErrorCould not find the association :collection_items in model Article
          
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.0/lib/active_record/reflection.rb:169:in `check_validity!'
          /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.0/lib/active_record/associations/has_many_through_association.rb:6:in 
    `initialize'
          /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.0/lib/active_record/associations.rb:865:in `new'
          
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.0/lib/active_record/associations.rb:865:in `articles'
          /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.0/lib/active_record/associations.rb:860:in 
    `articles'
          ./test/unit/test_collection.rb:22:in `test_how_many_articles' 

    What am I missing here? Am I not understanding has_many :through or is this a bug?

  13. #13
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My god that was painful!

    Finally found the problem.

    found it here: wiki.rubyonrails.org

    It should be made clear that the models for using through need to include an association for the through join, ie:
    PHP Code:
      class Product ActiveRecord::Base
        has_many 
    :catalogue_items
        has_many 
    :catalogues, :through => :catalogue_items
      end 
    If you donít include the join association you will get an HasManyThroughAssociationNotFoundError error stating: Could not find the association :catalogue_items in model Vendor
    I might be an idiot, and it might say this somewhere in the docs, but I struggled with this for a while, and couldnít find anything on the subject.
    Thanks again Luke for your help.

  14. #14
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, I'm back with a new issue.
    It seems that trying to add an article to a collection:
    PHP Code:
    my_collection.articles << new_article
    my_collection
    .save 
    does not work. However, it did with habtm.
    Any ideas on why?

  15. #15
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Mike, unfortunately you cannot do that as your has_many through relationships do not act as proxy collections.

    Article here:
    http://blog.hasmanythrough.com/artic...xy-collections

    Try this instead:

    Code:
    my_collection.collection_items.create(:article => new_article)

  16. #16
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Luke,
    Thanks, I actually stumbled on that late last nite.
    from that article:
    PHP Code:
     pat.skills.size             # => 4
     
    pat.skills(true).size       # => 5 
    what does (true) do?

    Also, to remove I assumed would be like create:
    PHP Code:
     collection_items.remove(item
    apparently not:
    PHP Code:
     NoMethodErrorundefined method `remove' for CollectionItem:Class 

  17. #17
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is what I've come up with for removing:
    PHP Code:
    items collection_items.find(:all, :conditions => "article_id = #{article.id}")
    items.each {|ii.destroy 

  18. #18
    Resident Java Hater
    Join Date
    Jul 2004
    Location
    Gerodieville Central, UK
    Posts
    446
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by MikeShank
    Here is what I've come up with for removing:
    PHP Code:
    items collection_items.find(:all, :conditions => "article_id = #{article.id}")
    items.each {|ii.destroy 

    If you look about, on your associations you can use :dependant => :destroy to do that for you, there is a :delete_all option, that saves some processing overhead if there is no need for any callbacks for model destruction. ....

    http://api.rubyonrails.com/classes/A...ssMethods.html

    explains it all in more detail
    http://virtualfunction.net - Rails Web Development
    http://squaremove.co.uk - Rails powered Property Listings

  19. #19
    SitePoint Zealot
    Join Date
    May 2001
    Posts
    193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks MiiJaySung, I did finally come to find that out.


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
  •