9

We are planning to upgrade our application to Rails3. One plugin we've used quite a bit is nested_has_many_through. This plugin seems outdated, and no longer maintained, and simply does not appear to be working in a new Rails3 application.

A simple example:

Author.rb
has_many :posts
has_many :categories, :through => :posts, :uniq => true
has_many :related_posts, :through => :categories

Post.rb
belongs_to :author
belongs_to :category

Category.rb
has_many :posts

Can anyone recommend the best practice way to handle this, or a working Rails3 plugin?

Thanks!!

releod
  • 513
  • 5
  • 12
  • 1
    Haha I just found your fork http://github.com/releod/nested_has_many_through and remembered this question and was coming here to tell you all about the fork. And then I saw your username. Good work, I just tested this on my Rails 3 app and it is (mostly) working. I've been spending all night trying to patch Rails directly as per https://rails.lighthouseapp.com/projects/8994/tickets/1152-support-for-nested-has_many-through-associations but getting stuck. I'll start with your fork as a template, and I might get further now! – Bo Jeanes Sep 23 '10 at 13:24
  • +1 http://github.com/releod/nested_has_many_through your rails3 fork works for me too, will use it until rails 3.1 – clyfe Mar 21 '11 at 15:26

3 Answers3

7

This is built in with Rails 3.1: http://asciicasts.com/episodes/265-rails-3-1-overview

David Phillips
  • 10,723
  • 6
  • 41
  • 54
  • Rails giveth and Rails taketh away http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-3-2-to-rails-4-0-active-record – engineerDave Mar 24 '15 at 21:17
0

I'm more confused by the has_many :related_posts part. Are you trying to essentially join together categorized posts? Like, all posts in 'x' category are considered 'related'? If so, this won't work based on there not being a RelatedPost class, so to fix this at a bare minimum, you'd have to specify :class_name on the association:

has_many :related_posts, :class_name => 'Post', :through => :categories

But secondly, it's probably not the correct approach to begin with. Since any author already has_many posts via the author_id foreign key, there is no sense in trying to weave back through the categories table, instead use grouping logic.

Alternate approaches that clean this up:

Author.rb

has_many :posts do
  def related
    all.group_by(&:category_id)
  end
end
author.posts.related
=> OrderedHash

Of course, all of this is moot if it wasn't what you were trying to accomplish. :P

jenjenut233
  • 1,938
  • 16
  • 13
  • 2
    I'm inclined to think his example is contrived (hence easily flawed). His question is still fundamentally important. And to the best of my knowledge there is NOT a working solution for nested has many throughs in Rails 3 (a la the old nested_has_many_through for Rails < 2.3) – Bo Jeanes Sep 22 '10 at 07:40
  • The latter part of his question mentioned "recommending the best practice". My point was, if your app requires it, there is probably a better mechanism for achieving it. ;) If his example truly is contrived, it would be incredibly helpful to see his actual code. – jenjenut233 Sep 23 '10 at 22:41
  • 1
    Fair enough. There are definitely use cases where a nested has many association (i.e. using multiple INNER JOINs, for the non-Rails folk) is a valid solution, and often the best one. Given "Author -< articles -< subscriptions >- subscribers >-< interests", `Author.subscribers` and `Author.subscriber_interests` would both be candidates for using the nested has many through, in my opinion. The other option is to cache those associations any time the 1st-level associations change, which is less than ideal. – Bo Jeanes Sep 23 '10 at 22:54
0

Rails 3 (untested, orders by posts with most related categories first):

category.rb:

class Category < ActiveRecord::Base
  class << self
    def posts
      Post.joins(:categories).
           where(:categories => select('id').all.map(&:id)).
           group('posts.id').
           order('count(*) DESC')
    end
  end
end

Usage:

related_posts = author.categories.posts
jimworm
  • 2,731
  • 18
  • 26