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
Related
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
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
I have users and projects. User can have many projects and project can have many users. Now project has a particular user as an author or the creator, ie. project has one creator and that creator is also a user. How do I map this relation in rails !!!
#Project
has_and_belongs_to_many :users
belongs_to :author, :class_name => "User"
#User
has_and_belongs_to_many :projects
has_many :authored_projects, :class_name => "Project", :foreign_key => "author_id"
And you need to add author_id to the projects table.
So you can use: project.author, user.authored_projects, etc
Try this
class User < ActiveRecord::Base
has_and_belongs_to_many :projects
has_many :created_projects, :class_name => "Project", :foreign_key => "creator_id"
end
class Project< ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :creator, :class_name => "User"
end
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
I have a User model which has many projects and a Project model which can have many users, but also belongs to a single user (ie the user who created this project). It must belong to a User. It also allows a list of users to be associated with it, think collaboration.
With this in mind, my models look like this:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
end
class AssignedProject < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Now, when I want to create a new project through a User, this is how I would do it:
user = User.create(:name => 'injekt')
user.projects.create(:name => 'project one')
Now, I know that projects is provided through an AssignedProject join model, which is why project.user will return nil. What I'm struggling to get my head around is the best way to assign the project creator (which by the way doesn't need to be user, it could be creator or something else descriptive, as long as it is of type User).
The idea then is to create a method to return projects_created from a User which will select only projects created by this user. Where user.projects will of course return ALL projects a user is associated with.
Assuming this kind of association is fairly common, what's the best way to achieve what I want? Any direction is greatly appreciated.
Add a creator_id column to your projects table for the creator relationship, and then add the associations to the models:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
I wanted to add little improvement to design. We don't actually need intermediate model because it does not contain any extra column other than reference_ids hence HABTM association is best suited over here.
class User < ActiveRecord::Base
has_and_belongs_to_many :projects, :join_table => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end