How can I relate to an object twice in rails? - ruby-on-rails

I've got a Users model and a Tasks model.
A task has a creator, of type user, and an assignee of type user.
I've already done a migration of AddUserIdtoTasks to get the creator relation working, but now I need to do the same thing again to add the assignee, but I'm already using the keyword 'user'. How should I go about building a proper relation.
A task only has one assignee, always.
I'm using devise for the user model.

has_one :creator, :class_name => "User"
has_one :asignee, :class_name => "User"
Or belongs_to, depending on how your fields are set up. has_one and belongs_to both take an optional :class_name argument for cases just such as yours.

Create the field assignee_id in your Task model and then use it for the relation as in
class Task < AR::Base
belongs_to :assignee, :class_name => 'User'
end
On the other side of the relation
class User < AR::Base
has_many: :assigned_tasks, :class_name => 'Task', :foreign_key => :assignee_id
end
Sorry, should be :class_name. Updated User class also with a :foreign_key parameter, without it user.assigned_tasks would have joined records using the :user_id parameter (the default value for has_many, i.e. "#{class_name}_id"`).
I invite you to read the link I've posted, it explains better than me all these things.
Source: http://guides.rubyonrails.org/association_basics.html#detailed-association-reference

Related

Rails many to many relationship confusion

So im working on a rails app for users to create events (and attend other created events). You can read about the assignment here (for the Odin Project): https://www.theodinproject.com/courses/ruby-on-rails/lessons/associations
Anyways I thought I had understood many to many relationships in rails, but the way i've seen other people write the models is confusing to me.
To me it seems like it should be something like:
class User < ApplicationRecord
has_many :attendances
has_many :events, through: :attendances
end
class Attendance < ApplicationRecord
belongs_to :user
belongs_to :event
end
class Event < ApplicationRecord
has_many :users
has_many :users, through: :attendances
end
This makes sense to me because a User can create many events, and an event can have many users attending. (Although attendances is probably the wrong word, maybe invites or something).
But i've seen some weird examples (You can see others source code below on the project) and it seems like they are adding much more to the models and also renaming the source/foreign_key/class_name.
Am I missing something? This still allows a user to "own" an event right? Maybe im mis-understanding how many-to-many works. But this fits at least in my mind of how it should be.
For reference some other models I was seeing was similar to this:
class Event < ActiveRecord::Base
belongs_to :creator, :class_name => "User"
has_many :event_attendees, :foreign_key => :attended_event_id
has_many :attendees, :through => :event_attendees
end
class EventAttendee < ActiveRecord::Base
belongs_to :attendee, :class_name => "User"
belongs_to :attended_event, :class_name => "Event"
end
class User < ActiveRecord::Base
has_many :created_events, :foreign_key => :creator_id, :class_name => "Event"
has_many :event_attendees, :foreign_key => :attendee_id
has_many :attended_events, :through => :event_attendees, :foreign_key => :attendee_id'
end
Basically similar things to the above. Im not really sure what this is doing? Or why all the extra is necessary.
In your example everything according to conventions. Maybe except many-to-many table naming.
attendances table has 'user_id' and 'event_id' fields. But in case it could conflict with other fields, or not descriptive enough you could use different keys.
belongs_to :creator, :class_name => "User"
belongs_to :creator by default would look for Creator model, so it is needed to specify class name explicitly, like in the provided example.
has_many :event_attendees, :foreign_key => :attended_event_id
By default foreign key would be event_id, so here it is specified explicitly too.
has_many :created_events, :foreign_key => :creator_id, :class_name => "Event"
By default, rails would look for user_id foreign key and CreatedEvent model. And these attributes specified explicitly.
You just need to understand what attributes rails provides by default, to change if it is required.
ActiveRecord associations default to a class and foreign key with the same name as the association. The code here is specifically specifying these because they are not the default.

Rails model advice

I need some suggests for the model relationship that I'm going to develop:
I want to create a research table that keep track of all the reasearches performed inside the platform.
In the platform I'm developing, an user can search for other users.
In order to do it, I thought to create 3 fields in the research table: Performer (user_id that submit the research) Research_string (The string that the performer submit) and Results (that is one or more user).
Of course the relationship among user and research tables will be many to many, but note that the research table has 2 different column that involves the user_id (performer and results) so how can I specify to rails ? I thought something like that :
class User < ActiveRecord::Base
has_many :performed_research, :through => :research_table
class Research < ActiveRecord::Base
has_many :users
But how can I specify that the has_many users in the Research tables implies two different relations depending by the column ?
Tnx
EDITED: my solution
Your solution is not correct, because the user has only the research performed and not the research where he is resulted. I made another solution, that it's not the best of clear but it works, I would like to have your judge:
class Research < ActiveRecord::Base
belongs_to :searcher, :class_name => 'User', :foreign_key=> 'submitter_id'
has_many :found_users, :through=>:user_researches,:source=>:user
#It is necessary to let the association work without class_name it would look for
userResearch class
has_many :user_researches, :class_name =>'User_research'
end
class User_research < ActiveRecord::Base
belongs_to :user
belongs_to :research
end
class User < ActiveRecord::Base
# It returns a list of research performed by the user
has_many :researches, :foreign_key => 'submitter_id'
# It is necessary to let the searcher relationship works
has_many :user_researches, :class_name =>'User_research'
#==> Searcher will return an Array of research where the user's skill has been researched
has_many :follower_researches, :through => :user_researches, :source=>:research
end
I say that it;s not the best because the follower_research of the user model, show an array of research when he has been results ... and not an Array of submitter that searching him, so to obtain them, I have to scroll the array of research and then take the searcher field ... Are you able to perform an improvement (hopefully less complex than this)
Do you mean something like this?
class User < ActiveRecord::Base
has_many :research_entries
class ResearchEntry < ActiveRecord::Base
has_one :performer, :class_name => 'User'
has_and_belongs_to_many :resulting_users, :class_name => 'User'
Update: I changed this to use the has_and_belongs_to_many relationship which will allow you to use a join table to connect many users into "resulting_users" field of the ResearchEntry
Something like this:
class User < ActiveRecord::Base
has_many :submitted_researches, :class_name => 'Research', :foreign_key => 'submitter_id'
has_manu :researches, :through => :performed_researches
class Research < ActiveRecord::Base
belongs_to :submitter, :class_name => 'User'
has_many :researchers, :through => :performed_researches, :class_name => 'User'
class PerformedResearch < ActiveRecord::Base
belongs_to :user
belongs_to :research
See: http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association
Update: I think I misread something. What is results? and how is it related to users?
Update 2: Still not sure I understand but here's another stab
I originally thought you were doing something related to academic research and the Research model was for research papers with the performer being scientists that did the research.
From re-reading your question I'm now thinking you have a rails application with some users and a search feature that lets a user search for other users and for each search you are trying to keep track of which user did the search and which users they found.
Let me know if any of these assumptions are wrong.
Based on that:
class User < ActiveRecord::Base
has_many :searches #all the searches this user performed
class Search < ActiveRecord::Base
belongs_to :searcher, :class_name => 'User' # the user who performed the search
has_many :found_users, :though => :user_search_results, :foreign_key => 'user_id' # using foreign_key because I want to change the name to 'found_users'
#alternatively if you don't want to use foreign_key use the line bellow instead
#has_many :users, :thorough => :user_search_results
class UserSearchResult < ActiveRecord::Base
belongs_to :user
belongs_to :search

belongs_to and has_many to the same model

I am wondering whether there is a way to do this with rails or not. Basically I have a user model and an event model. Event is created by a user and I want to have a foreign key (user_id) in the event model that indicates who created the event. Additionally, event can have many users who attend it so the event model becomes something like
belongs_to :user
has_many :users, :through => :guests #suppose i have the guest model
and the user model looks something like
has_many :events, :through => :guests
I have not tried this association yet but I want to be able to say
e = Event.find(1)
e.creator #returns the user who created this event
instead of
e.user
is there a way for me to do this?
Simply pass some options to belongs_to:
belongs_to :creator, :class_name => "User", :foreign_key => "user_id"
This specifies that the creator method will be a User object, referencing the user_id field.

How can I have two columns in one table point to the same column in another with ActiveRecord?

I run the risk of palm-to-forehead here, but I can't quite figure out how to do this with Rails' ActiveRecord sugar.
I have a tickets table that has two columns (submitter_id and assignee_id) that should each reference a different user from the users table (specifically the id column in the users table). I'd like to be able to do things like ticket.submitter.name and ticket.assignee.email using ActiveRecord's associations. Submitter and Assignee are simply user objects under different associative names.
The only thing I've found that comes close to what I am doing is using polymorphic associations, but in the end I'm fairly certain that it's not really what I need. I'm not going to have multiple types, both submitter and assignee will be users, and very well could be two different users.
Any help would be fantastic. Thanks!
class Ticket < ActiveRecord::Base
belongs_to :submitter, :class_name => "User"
belongs_to :assignee, :class_name => "User"
end
Should work.
Edit: Without trying it out, I'm not sure whether you need the :foreign_key parameter or not. My instinct is not, but it couldn't hurt.
Edit again: Sorry, left off the User -> Ticket associations. You didn't mention using them, and I typically will only add associations in one direction if I don't plan on using them in the other direction.
Anyway, try:
class User < ActiveRecord::Base
has_many :assigned_tickets, :class_name => "Ticket", :foreign_key => "assignee_id"
has_many :submitted_tickets, :class_name => "Ticket", :foreign_key => "submitter_id"
end
Something like this should work
class Ticket < ActiveRecord::Base
belongs_to :submitter, :class_name => 'User', :foreign_key => 'submitter_id'
belongs_to :assignee, :class_name => 'User', :foreign_key => 'assignee_id'
end
class User < ActiveRecord::Base
has_many :tickets, :class_name => 'Ticket', :foreign_key => 'submitter_id'
has_many :tickets_assigned, :class_name => 'Ticket', :foreign_key => 'assignee_id'
end
Yes, PreciousBodilyFluids is right we don't need to specify the foreign_key in the Ticket class as rails can infer it from the column name, i.e. submitter_id and assignee_id
But if your association name is different from the column_name_{id} then you will have to specify it, i.e. the User class case

Rails associations with the same models

I have two classes with the following associations:
class Incident
has_one :assignee
has_one :technician
class User
has_many :incidents
Note that the assignee and technician fields refer to objects of type User. How should these relationships be in the model?
Presumably the Incident should belong_to an assignee and technician, because the foreign key holding those relationships would be in the incidents table, not the employees table
class Incident
belongs_to :assignee, :class_name => 'User'
belongs_to :technician, :class_name => 'User'
class User
has_many :assigned_incidents, :class_name => 'Incident', :foreign_key => 'assignee_id'
# not sure the wording you'd want to use for this relationship
has_many :technician_incidents, :class_name => 'Incident', :foreign_key => 'technician_id'
You would want the foreign key fields to be incidents.assignee_id, incidents.technician_id
Here's a complete answer to this issue, in case people visiting this question are having a hard time putting everything together (as I was when I first looked into this).
Some parts of the answer take place in your Migrations and some in your Models:
Migrations
class CreateIncidents < ActiveRecord::Migration
create_table :incidents do |t|
def up
t.references :assignee
t.references :technician
end
end
end
Here you are specifying that there are two columns in this table that will be referred to as :assignee and :technician and which hold references to another table. Rails will actually create columns called 'assignee_id' and 'technician_id' for you. In our case they will each reference rows in the Users table, but we specify that in the models, not in the migrations.
Models
class Incident < ActiveRecord::Base
belongs_to :assignee, class_name => 'User'
belongs_to :technician, class_name => 'User'
end
Here you are creating a property on the Incident model named :assignee, then specifying that this property will be referencing an instance of the User class. Rails, seeing the 'belongs_to', will look for a column in your database called 'assignee_id', which we defined above, and use that to store the foreign key. Then you're doing the exact same thing for the technician.
This will allow you to access your assignee and technician, both instances of the User model, through an instance of the Incident model, like this:
Incident.assignee.name
Incident.technician.email
Here is your User Model:
class User < ActiveRecord::Base
has_many :assigned_incidents, :class_name => 'Incident', :foreign_key => 'assignee_id'
has_many :incidents_as_technician, :class_name => 'Incident', :foreign_key => 'technician_id'
end
Here you are creating a property on the User Model named :assigned_incidents, specifying that this property will be referencing instances of the Incident Model, and that the foreign key on the Incident model which references this, the User Model, that we want to use to for this property is called 'assignee_id'. Then you are doing the same thing for incidents_as_technician (this naming seems kind of awkward, but without better knowledge of what you're trying to do, I don't really have any great suggestions).
This allows you to get all of a user's assigned incidents or incidents as technician by doing this:
User.assigned_incidents
User.incidents_as_technician
Doing either of these will return an array of instances of the Incident model.

Resources