Stéphane V
Stéphane V

Reputation: 1094

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

Upvotes: 1

Views: 88

Answers (2)

pcg79
pcg79

Reputation: 1283

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.

Upvotes: 1

St&#233;phane V
St&#233;phane V

Reputation: 1094

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

:-)

Upvotes: 0

Related Questions