Get data through many to many relations - ruby-on-rails

I have 3 tables:
User class
User has_many :project_assignments
User has_many :projects, through: :project_assignments
ProjectAssignment class
ProjectAssignment belongs_to :user
ProjectAssignment belongs_to :project_owner, class_name: 'User', foreign_key: 'user_creator_id'
ProjectAssignment belongs_to :project
Project
has_many :project_assignments
has_many :users, through: :project_assignments
ProjectAssignment has the columns:
project_id, user_id, creator_user_id
I want to get all the projects, for a user through creator_user_id
ex: current_user.created_projects
The query: ProjectAssignment.where(creator_user_id: current_user.id)
Can it be done when defining the relations in the models, the same as I did with projects but the foreign_key should be creator_user_id

I think you just need another couple of associations in User which leverage the creator_user_id field (as opposed to user.projects which will return the projects the user is a member of)
Try this -
#in User class
has_many :owned_project_assignments, :class_name => "ProjectAssignment", :as => :project_owner, :foreign_key => "user_creator_id"
has_many :owned_projects, :through => owned_project_assignments, :class_name => "Project", :source => :project, :as => :project_owner
the :source and :as options can be a bit tricksy, so this might not work, it's just off the top of my head...

In my case this was the correct solution:
has_many :owned_project_assignments, class_name: "ProjectAssignment", foreign_key: 'user_creator_id'
has_many :owned_projects, through: :owned_project_assignments, source: :project

Related

Polymorphic Associations for Multiple User Roles in Rails

I'm a designer/HTML+CSS dev learning Rails, and I'm having trouble with multiple user roles. My main models are as follows:
Studio
has_many :locations, dependent: :destroy
has_many :events, through: :locations
has_many :teachers, through: :events
Location
belongs_to :studio, :class_name => Studio, :foreign_key => "studio_id"
has_many :events
has_many :teachers, through: :events
Event
belongs_to :location, :class_name => Location, :foreign_key => "location_id"
belongs_to :studio
has_many :teachers
Teacher
belongs_to :event, :class_name => Event, :foreign_key => "event_id"
belongs_to :location
belongs_to :studio
has_one :user, :as => :roleable
accepts_nested_attributes_for :user
User
belongs_to :roleable, :polymorphic => true
The Teacher/User relationship is the tricky bit; I'm not sure if it should be reversed.
Users have basic profile info, Teachers have many details. All users can follow teachers, but teachers can also invite new teachers, and list other teachers as influences. I had this set up as
Teacher
has_many :guests, class_name: "Teacher", foreign_key: "host_id"
belongs_to :host, class_name: "Teacher"
has_many :influences, class_name: "Teacher", foreign_key: "student_id"
belongs_to :student, class_name: "Teacher"
User
has_many :favorites, class_name: "User", foreign_key: "fan_id"
belongs_to :fan, class_name: "User"
Does this look right, or should I say that User has_one :teacher ? The latter seems more correct, but it made my views really difficult. Thanks in advance!

Rails has_and_belongs_to_many with Many

I'm working on a Rails 4 app with complex associations and i cant figure out how to join one model to a parent.
Basically my apps logic is as follows
User
- belongs_to :account, polymorphic: true
Developer
- has_one :user, as: :account
- has_and_belongs_to_many :organizations
Organization
- has_one :user, as: :account
- has_and_belongs_to_many :developers
I decided to go this route over a STI because this allowed me to make my apps migration file cleaner and more organized
So there can be a Developer by itself and there can also be and Organization which holds many Developers, so i added has_and_belongs_to_many :organizations and has_and_belongs_to_many :developers to create this relationship. So everything works here in my app if i look up User.find().account.developers or User.find().account.organizations i get the associated records.
Now we get to the part where i am having trouble. Within my Rails app i have a model called App. A Developer can create many Apps by itself or a Developer can create and Organization and create many Apps within that Organization that all of the Developers who belong to that Organization have access too. I have no idea how to implement a relationship like this. Any suggestions?
Developer
has_one :user, as: :account
has_many :apps, as: :appable
has_and_belongs_to_many :founding_organizations, class_name: 'Organization', foreign_key: :founder_id
has_and_belongs_to_many :collaborating_organizations, class_name: 'Organization', foreign_key: :collaborator_id
has_and_belongs_to_many :organizations (Should this stay?)
Organization
has_one :user, as: :account
has_many :apps, as: :appable
has_and_belongs_to_many :founders, class_name: 'Developer', association_foreign_key: :founder_id
has_and_belongs_to_many :collaborators, class_name: 'Developer', association_foreign_key: :collaborator_id
has_and_belongs_to_many :developers (Should this stay?)
App
belongs_to :appable, polymorphic: true
/app/models/app.rb
App < ActiveRecord::Base
belongs_to :appable, :polymorphic => true
end
/app/models/organization.rb
Organization < ActiveRecord::Base
has_and_belongs_to_many :founders, :class_name => 'Developer', :association_foreign_key => :founder_id, :join_table => 'founders_organizations'
has_and_belongs_to_many :collaborators, :class_name => 'Developer', :association_foreign_key => :collaborator_id, :join_table => 'collaborators_organizations'
has_many :apps, :as => :appable
# Other relationships
end
/app/models/developer.rb
Developer < ActiveRecord::Base
has_and_belongs_to_many :founded_organizations, :class_name => 'Organization', :foreign_key => :founder_id, :join_table => 'founders_organizations'
has_and_belongs_to_many :collaborated_organizations, :class_name => 'Organization', :foreign_key => :collaborator_id, :join_table => 'collaborators_organizations'
has_many :apps, :as => :appable
# Other relationships
end
If you want a HABTM association. you need a join table. In Rails 4, you can add a migration file containing this:
create_join_table :developers, :organizations
Then just use:
Developer.find().organizations
or
Organization.find().developers
If you use User.find().account. you must get account's class first, then decide to use developers or organizations

polymorphic and one-to-many association

I have a Collaboration model with a polymorphic association with a Grade | School, and a one-to-many association with a User
belongs_to :owner, polymorphic: true
belongs_to :user, foreign_key: "teacher_id"
this is the way i manage the users who can access a school or a grade. Now, what i need is to do something like this
School.first.teachers
Grade.first.teachers
I think it would be something like this in the Grade/School model
has_many :teachers, through: :collaborations, foreign_key: "teacher_id"
but it doesn't seem to be the right solution. Any ideas?
has_many :collaborations, :as => :owner
has_many :teachers, :through => :collaborations, :source => :user
You need to establish the polymorphic association to collaborations. Try:
class School < ActiveRecord::Base
has_many :collaborations, :as => :owner
has_many :teachers, :through => :collaborations
end

has_many through in Ruby on Rails app

In my rails app a user can create courses and schools (group). Each time a user creates a course or school their user_id is stored in the database table for the course or school, so a user has_many :schools and :courses and the school or course belongs_to :user. Also, the user can can attend courses and join schools (as student or professor) with a has_many through relationship model (schoolgroups for schools which has a :user_id, school_id, and :role [string], and for courses student_users (and professor_users) which has a :user_id, course_id, and :role [string]. My question is, in the user model can I just specify once that:
has_many :schools, :dependent => :destroy
has_many :courses, :dependent => :destroy
has_many :schoolgroups, :dependent => :destroy
has_many :student_users, :dependent => :destroy
has_many :professor_users, :dependent => :destroy
or would I have to have a user model that looked like this:
has_many :schools, :dependent => :destroy
has_many :courses, :dependent => :destroy
has_many :schoolgroups, :dependent => :destroy
has_many :schools, :through => :schoolgroups
has_many :student_users, :dependent => :destroy
has_many :courses, :through => :student_users
has_many :professor_users, :dependent => :destroy
has_many :courses, :through => :professor_users
You'll need to think about the ownership of the models in a bit more detail. has_many means a many-to-one relationship, so saying Professor has_many Courses means that the professor owns the courses and the course only has one professor (or does it?). So you'll do something like this:
has_many :school, :dependent => :destroy
has_many :courses, :dependent => :destroy
has_many :schoolgroups, :dependent => :destroy
On the other hand, you'll have things that the user is associated to, but other users may also be associated in the same way. For example, a user can be a student in a course, but so can many other students. For this you'll want to use has_and_belongs_to_many or HABTM which represents a many-to-many relationship:
has_and_belongs_to_many :courses_as_student, :class_name => "Course",
:join_table => "student_users"
Then in the Course class:
belongs_to :user
# or even better:
# belongs_to :professor, :class_name => "User", :foreign_key => "professor_id"
has_and_belongs_to_many :students, :class_name => "User",
:join_table => "student_users"
You can read all the details in the Rails documentation.

What is the best way to handle 4 way relation between 2 models?

I have two models: Company and User
This is the situation:
Company can follow another company
User can follow a company
User can follow another user
What is the best way to define the relationships and how will the join model look like?
Also, are there any best practises when addressing such situations?
Update
Sorry, to have not mentioned this earlier. I am aware of the various relationship types available. My question is 'which is the best fit'?
Regarding your question I would suggest you to go through couple of Railscasts videos:
http://railscasts.com/episodes/47-two-many-to-many
http://railscasts.com/episodes/154-polymorphic-association
And this is described very well on RubyonRails website
http://guides.rubyonrails.org/association_basics.html
I would say look these for your case:
http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association
http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association
I hope this will help you.
Thanks to polymorphic associations, we can put all relations into one table which like this:
create_table :follows do |t|
t.references :followable, :polymorphic => true
t.references :followed_by, :polymorphic => true
end
Then the models are:
class User < ActiveRecord::Base
has_many :following_objects, :class_name => 'Follow', :as => :followed_by
has_many :followed_objects, :class_name => 'Follow', :as => :followable
end
class Company < ActiveRecord::Base
has_many :following_objects, :class_name => 'Follow', :as => :followed_by
has_many :followed_objects, :class_name => 'Follow', :as => :followable
end
class Follow < ActiveRecord::Base
belongs_to :followable, :polymorphic => true
belongs_to :followed_by, :polymorphic => true
end
Sorry for the ugly names.
A basic idea would be to use two self-referencing assocations:
User -> Friendship <- User
Company -> Partnership <- Company
models/user.rb
has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
models/friendship.rb
belongs_to :user
belongs_to :friend, :class_name => "User"
models/company.rb
has_many :partnerships
has_many :partners, :through => :partnerships
has_many :inverse_partnerships, :class_name => "Partnership", :foreign_key => "partner_id"
has_many :inverse_partners, :through => :inverse_partnerships, :source => :company
models/partnership.rb
belongs_to :company
belongs_to :partner, :class_name => "Company"
And one many-to-many assocation:
User -> CompanyUser <- Company
models/user.rb
has_and_belongs_to_many :companies
models/company.rb
has_and_belongs_to_many :users
So for this implementation you will need 5 tables (users, friendships, companies, partnerships and companies_users) if you are using a RDBMS.
You can get a nice example in this screencast:
http://railscasts.com/episodes/163-self-referential-association

Resources