Search code examples
ruby-on-railsassociationsmodelsmodel-associations

Multi level nested association shortcuts


I'm having trouble with associations. Basically, Users have groups (not shared with anybody). Each group has clients, projects and tasks.

Should I define something like:

class User < ActiveRecord::Base 
  has_many :groups 
  has_many :clients, through: :groups
  has_many :projects, through :clients #(could be groups?) 
  has_many :task, through :groups 
end

is this the proper way of doing it? I just want, from each user, list all their task, groups and clients. Is it ok to 'travel' through the models like this? I've followed some RoR tutorials and books, but all of them deal with less models.

basic rough model


Solution

  • You can navigate through like you want. Here is explained the case when you want a shortcut through nested has_many associations (search a little below the link I posted).

    So given this explanation, for this to work you need to do the following (you were close to it):

    class User < ActiveRecord::Base
      has_many :groups 
      has_many :clients, through: :groups
      has_many :projects, through :groups
      has_many :tasks, through :groups 
    end
    
    class Group < ActiveRecord::Base
      belongs_to :user
    
      has_many :clients
      has_many :projects, through :clients
      has_many :tasks, through :clients 
    end
    
    class Client < ActiveRecord::Base
      belongs_to :group
    
      has_many :projects
      has_many :tasks, through :projects 
    end
    
    class Project < ActiveRecord::Base
      belongs_to :client
    
      has_many :tasks
    end
    
    class Task < ActiveRecord::Base
      belongs_to :project
    end
    

    Another way (and maybe shorter) to set this up would be (look here for where both strategies are documented):

    class User < ActiveRecord::Base
      has_many :groups 
      has_many :clients, through: :groups
      has_many :projects, through :clients
      has_many :tasks, through :projects 
    end
    
    class Group < ActiveRecord::Base
      belongs_to :user
    
      has_many :clients
    end
    
    class Client < ActiveRecord::Base
      belongs_to :group
    
      has_many :projects
    end
    
    class Project < ActiveRecord::Base
      belongs_to :client
    
      has_many :tasks
    end
    
    class Task < ActiveRecord::Base
      belongs_to :project
    end
    

    Hope it helps!