get name of object following 2 time a relationship (2x has_many)

I have an author, who writes products, which are placed in groups. What I want to do is to list the groups that an author is involved into.

So, I have first to follow the link from author to products, which works with :

@author = Author.find(params[:id])
@products = @author.products

which gives lot of products :-) Then I have to find (all) the groups that are linked to all of the products (because a group can contain a lot of products, I have already a has_many link with group_id column in the product table)

But when I try to write something as

@groups = @author.products.groups

I get the error : undefined method `groups' for # Class:0x000000032a2198

Why ?

Here is the model, where only the "through" clauses seem not to work ?

class Author < ActiveRecord::Base
  has_and_belongs_to_many :products
  has_many :groups, :through => :products
end
class Product < ActiveRecord::Base
  belongs_to :group
  has_and_belongs_to_many :authors
end
class Group < ActiveRecord::Base
  has_many :products, :dependent => :destroy
  has_many :authors, :through => :products
end

Thanks !

Edit : I found an ugly way to do what I want. But is there no better RoR way ??

def show
@author = Author.find(params[:id])
    @products = @author.products
    @groups = []
    @products.each do |product|
        group = Group.find(product.group_id)
        unless @groups.include?(group)
            @groups << group
        end
    end
end

Answers


As far as I know there's no way to do it in a Rails way. First, here's how to make what you have more "Railsy":

def show
  @author = Author.find(params[:id])
  @products = @author.products
  @groups = []
  @products.each do |product|
    unless @groups.include?(product.group)
      @groups << group
    end
  end
end

But a shorter way would be:

@products.map(&:group).uniq

Quick explanation of what it's doing. First it's using the symbol to proc shorthand that was introduced in Rails 1.1 (http://blog.hasmanythrough.com/2006/3/7/symbol-to-proc-shorthand). That builds an array of groups. Then b/c, in your question, you are checking for uniqueness (using include?) I call .uniq which weeds out any duplicates.


I also found another way to do this :

@user = User.find(params[:id])
@groupcollect = []
@user.products.each { |e| @groupcollect << e.group_id}   # collect group_id for all products
@mygroups = Group.find(@groupcollect.uniq)        # gets the groups for all group_id, unique

:-)


Need Your Help

Unable to reduce cyclomatic complexity in a Factory method without using reflection

c# vb.net design-patterns reflection factory-method

In my factory method I use Switch statement to create concrete objects. This results in very high cyclomatic complexity. Here is a sample code:

Why is Google App Engine servlet getting old no more exist data from file?

google-app-engine

I have a Google App Engine servlet, it's supposed to go to my site and get a file, then display the content of that file on the servlet served page, the code looks like this :

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.