Search code examples
ruby-on-railsrubymany-to-many

Rails - how to list each object's object in many-to-many relations?


I have multiple models that have join tables, and i want to implement list of those items in controller.

Customer <- many -> Products
Products <- many -> Teams
Products <- many -> Documents

Models:

class Customer < ActiveRecord::Base
   has_many :cstprd_relations
   has_many :products, :through => :cstprd_relations
end

class Product < ActiveRecord::Base
  has_many :cstprd_relations
  has_many :customers, :through => :cstprd_relations

  has_many :teaprd_relations
  has_many :teams, :through => :teaprd_relations
end

class Team < ActiveRecord::Base
  has_many :teaprd_relations
  has_many :products, :through => :teaprd_relations
end

class Document < ActiveRecord::Base
  has_many :prddoc_relations
  has_many :products, :through => :prddoc_relations
end

And for example, document migrations:

class CreateDocuments < ActiveRecord::Migration
  def change
    create_table :documents do |t|
      t.string :name

      t.timestamps null: false
    end
  end
end

class AddDocumentRefToProducts < ActiveRecord::Migration
  def change
    add_reference :products, :document, index: true, foreign_key: true
  end
end

How to list unique documents that belongs to products and link them (docs) to teams?

Like this:

Customer1:

  • "Document 'Testing phase 1' for product 'Calc' is finished by teams 'QA, TestTeam, Dev'"
  • "Document 'Testing phase 2' for product 'Phone' is finished by teams 'QA, TechSpec, MarketingTeam'"
  • "Document 'Install Guide' for product 'App' is finished by teams 'Dev, TechSpec'"

Solution

  • Maybe this code shows how it could look like.

    Product.all.each do | prod |
      Document.products( prod.id ).teams.each do | team |
        # generate message
      end 
    end
    

    or based on Document

    Document.where( :id => id ).each do | doc |
      doc.products.each do | prod |
        prod.teams.each do | team |
          # generate you message
        end
      end
    end
    

    EDIT to answer the question in comments

    Customer.all.each do | cust |
      puts "Customer #{cust.name}"
      cust.products.each do | prod |
        prod.documents.each do | doc |
          print "* Document #{doc.name} for product #{prod.name} is finished by teams "
          puts "'" + prod.teams.map(&:name).join(', ') + "'"
        end 
      end
    end