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
Related
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
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
class Profile
has_many :projects, :through => "teamss"
has_many :teams, :foreign_key => "member_id"
has_many :own_projects, :class_name => "Project", :foreign_key => :profile_id
has_many :own_teams, :through => :own_projects, :source => :teams
end
class Project
belongs_to :profile, :class_name => "Profile"
has_many :teams
has_many :members, :class_name => "Profile", :through => "teams", :foreign_key => "member_id"
end
class Team
belongs_to :member, :class_name => 'Profile'
belongs_to :project
end
I need to create model Evaluation. What I want to do is generate a link in project#view page for each member of the project, including the owner, in order to make an Evaluation The person will click on the link and evaluate the person related to this link. The owner of the Project will evaluate all the members, and all the members will evaluate the owner.
I have defined model Evaluation as following, but I think I miss something:
class Evaluations < ActiveRecord::Base
belongs_to :evaluated, :class_name => 'Profile', :foreign_key => "evaluated_id"
belongs_to: :profile, :class_name => 'Profile', :foreign_key => "profile_id"
end
Remembering that Evaluation table will have tons of attributes, that's why I'm going not going with has_many_and_belongs_to_many.
How can I create this model in order to do what I want and be able to acess all I need via project#show page?
Thanks!
Edited
Changes done:
class Profile
has_many :evaluations, :dependent => :destroy, :foreign_key => :evaluation_id
has_many :evaluators, :through => :evaluations, :foreign_key => :profile_id
end
class Project
has_many :evaluations,:foreign_key => "project_id"
end
class Evaluations < ActiveRecord::Base
belongs_to :evaluated, :class_name => 'Profile', :foreign_key => "evaluated_id"
belongs_to: :profile, :class_name => 'Profile', :foreign_key => "profile_id"
belongs_to: :project, :class_name => 'Project', :foreign_key => "project_id"
end
You have your team and profile (member) associations a little messed up. A team has many profiles (members), and a profile (member) belongs to a team. Beyond that, you may just be over-complicating things. I'm curious as to why you wouldn't just call the Profile Model Member instead and keep things that much simpler?
That being said, you are doing a pretty complex set of associations. I would highly recommend you read the ActiveRecord Associations doc closely to get a firm understanding of how these things work, especially how primary and foreign keys are automagically determined.
I think below will get you what you want.
class Team
has_and_belongs_to_many :members,
:class_name => "Profile"
belongs_to :project
belongs_to :team_leader,
:class_name => "Profile"
end
class Profile
has_and_belongs_to_many :teams
has_many :projects,
:through => :teams
has_many :owned_projects,
:class_name => "Project",
:foreign_key => "owner_id"
has_many :owned_teams,
:class_name => "Team",
:foreign_key => "team_leader_id"
has_many :evaluations
has_many :evaluations_given,
:class_name => "Evaluation",
:foreign_key => "evaluator_id"
end
class Project
has_many :teams
belongs_to :owner,
:class_name => "Profile"
has_many :members,
:through => :teams
has_many :evaluations
end
class Evaluation
belongs_to :profile
belongs_to :evaluator,
:class_name => "Profile",
:foreign_key => "evaluator_id"
belongs_to :project
end
In support of these model definitions would be the following tables/keys:
evaluation
id
profile_id
evaluator_id
project_id
teams
id
project_id
team_leader_id
profiles
id
project
id
owner_id
profiles_teams
profile_id
team_id
With this, you should be able to access collections/objects that you need to get your links right such as:
project.members
project.owner
project.teams
team.project
profile.projects
profile.owned_projects
profile.teams
team.members
team.leader
project.evaluations
profile.evaluations
evaluation.evaluator
profile.evaluations_given
Note, also, that your nested resources are going to be just as complex, if you try to stay with a RESTFUL framework. Read up!
I have these models:
class Profile
has_many :projects, :through => "teams"
has_many :teams, :foreign_key => "member_id"
has_many :own_projects, :class_name => "Project", :foreign_key => :profile_id
has_many :own_teams, :through => :own_projects, :source => :teams
end
class Project
belongs_to :profile, :class_name => "Profile"
has_many :teams
has_many :members, :class_name => "Profile", :through => "teams", :foreign_key => "member_id"
end
class Team
belongs_to :member, :class_name => 'Profile'
belongs_to :project
end
I want to create model Evaluation. It will need the ID of the Project Owner, the ID of a Member of this Project, and the ID of the Project. Explaining better, The Owner of the Project will Evaluate all his members, one by one. And the members will evaluate just the owner of the project. The table Evaluation will have a lot of attributes plus those Ids mentioned before.
My question is: How would my models be to make it function with evaluation, and how would be model evaluation itself? has_and_belongs_to_many or has_many :through?
Thanks.
Edited
Shot in the dark
class Evaluations < ActiveRecord::Base
belongs_to :evaluated, :class_name => 'Profile', :foreign_key => "evaluated_id"
belongs_to: :evaluator, :class_name => 'Profile', :foreign_key => "profile_id"
end
Guess I won't need the ID from Project...
Project owner evaluates member performance for a project
Members will evaluate the project owner for his performance on a project
So, Evaluation has an evaluator, evaluee, a project, and other attributes
We also need to know the types of the evaluee and evaluator
Create 2 evaluation classes one for EmployeeEvaluation, one for ManagerEvaluation. Use Single table inheritance.
class Evaluation < ActiveRecord::Base
attr_accessible :evaluator, :evaluee
belongs_to :project
end
class EmployeeEvaluation < Evaluation #project manager evaluation of employee
def evaluator
Manager.find(self.evaluator)
end
def evaluee
Employee.find(self.evaluee)
end
end
class ManagerEvaluation < Evaluation
def evaluator
Employee.find(self.evaluator)
end
def evaluee
Manager.find(self.evaluee)
end
end