I got a case model. This case model has a client and an opponent field.
Both of them are Person models. A case has exactly one client and one opponent. Now a Person can be a client or it could be an opponent and a Person can have many cases.
How can i build this association in rails? When i split the Person model into a client and an opponent model it seems quite easy, but that does not seems very dry to me.
This is what i have at the moment
class Person < ActiveRecord::Base
has_many :cases
end
class Case < ActiveRecord::Base
belongs_to :client, class_name: 'Person'
belongs_to :opponent, class_name: 'Person'
end
This works so far, that i can add clients and opponents to a case.
But how can i find all the cases through a client or an opponent?
---old
when i have Client.first.cases my sql query is:
--new
of course i mean Person.first.cases-- since i dont have a clients table, just my id inside the Case table is called client_id or opponent_id
SELECT cases.* FROM cases WHERE cases.person_id = 3
Now this has to be the client id or the opponent id
Thanks for help
When you asks for Client.first.cases, In this query Active Record understand, you want all cases to be fetched that belongs to Person table's first record (which id is 3).
person_id is client_id, because first client's id in your person table is 3.
If you will write : Client.first, In your sql query you will see :
SELECT person.* FROM person WHERE person_id = 3
I think, you should try to pass a foreign_key constraint in you Case model like this:
class Case < ActiveRecord::Base
belongs_to :client, class_name: 'Person', foreign_key: "client_id"
belongs_to :opponent, class_name: 'Person',foreign_key: "opponent_id"
end
Thanks.
(~ last 10 minutes of) http://www.youtube.com/watch?v=AhFK0UO9VPs ~
Here is almost the explanation of my problem with a Person model and a Message model, where the Message Model has a receiver_id and a sender_id.
The foreign key is not needed at the Case model (to go back to my question), it is needed inside the Person model like this
class Person < ActiveRecord::Base
has_many :cases, foreign_key: "client_id"
end
so on a Person object i can use not person.cases and i will get all the cases, where this person is the client.
I still don't know, how to get the cases, where the person is the opponent
Related
My Seminar model has a column named teacher_id. That part of the relationship is working. I can call seminar.teacher to retrieve the User who teaches that seminar.
I'd like to be able to invert that query. In other words, I need to call teacher.own_seminars to get a collection of all the seminars where that User is listed as the teacher_id. I know that I could call Seminar.where(:teacher => teacher), but that's clunky. And I think that the performance is probably worse that way.
Note: Some of the Users are students who are linked to Seminar through the seminar_user join table, but I don't think that affects this question.
This is the model setup that isn't quite working yet
class User < ApplicationRecord
has_many :own_seminars, :class_name => "Seminar", foreign_key: 'own_seminar_ids'
end
class Seminar < ApplicationRecord
belongs_to :teacher, class_name: "User", foreign_key: 'teacher_id'
end
Cheers!
In foreign_key option, you specify the column which is, well, the foreign key.
The way has_many works, is it tries to guess, which one of the fields in the referenced entity corresponds to the primary key of this entity. By default, it's user_id (derived from name User). But since your column is actually called teacher_id, you should use that instead.
has_many :own_seminars,
class_name: "Seminar",
foreign_key: 'teacher_id'
In the app I am building to learn RoR, I have a model "Document" and a model "Business Partner". On the "Document" model, I have 2 fields ("Sender" and "Receiver") referring to the model "Business Partner".
How do I model twice a belongs_to the same target with different fields? What should the migration be?
Related question: how do I model the relationship to it self for business partner? i.e. one company has many business partners, yet can be a business partner too. Note - not to the same record (company A cannot have a relationship to company A (itself).
Assuming you've got columns sender_id and receiver_id for the sender and receiver relationships on your Document model (i.e. on your documents table), you can do something like this:
class Document < ActiveRecord::Base
belongs_to :sender, class_name: "BusinessPartner"
belongs_to :receiver, class_name: "BusinessPartner"
end
There's no particular migration for this as long as you've got those columns there on the table (if you've named them something else, just replace sender and receiver above by whatever column name minus the _id part).
And then for your BusinessPartner model:
class BusinessPartner < ActiveRecord::Base
has_many :sent_documents, class_name: "Document", foreign_key: "sender_id"
has_many :received_documents, class_name: "Document", foreign_key: "receiver_id"
end
Here, sent_documents will fetch all rows in the documents table where sender_id matches the id of the BusinessPartner, and similar for received_documents.
More info in the Rails docs.
Regarding your second question, there is a section of the Rails docs describing this, it is called "Self Joins". However, given that you want to model a many-to-many relationship, you will need a slightly special table arrangement. See this SO answer for some details on how to setup that arrangement. That is actually a somewhat tricky topic in itself, if you're interested in details I'd recommend asking a separate question on it (although that SO post answers it pretty well).
In my Rails app, I have the following models:
class User < ActiveRecord::Base
# user declaration
has_many :account
end
class Account < ActiveRecord::Base
belongs_to :user
end
I need to add another relation where each Account can be managed by multiple AccountManagers. However, AccountManagers themselves are also Users of this system (i.e. a User can both have an Account and manage another user's account).
I'm fairly new to Rails, and I know that I can just create another model called AccountManagers. I have a feeling that we don't NEED to make another model however; all the information contained within my proposed AccountManagers model is found in the Users model as well.
I've tried to add the following relationship to the Account model:
has_many :account_managers, through: :users, source: :users
where the Account has many managers, and each manager is declared from the User model. This doesn't work as the AccountManagers table doesn't exist (and the error in the view states that as well).
Is there a way to get this relationship to work?
You have to add another join table, say account_managements with columns and user_id and account_id
class User < ActiveRecord::Base
# user declaration
has_many :accounts
has_many :managed_accounts, :source => :account, :through => :account_managements
end
class Account < ActiveRecord::Base
belongs_to :user
has_many :account_managers, :source => :user, :through => :account_managements
end
and
class AccountManagement < ActiveRecord::Base
belongs_to :user
belongs_to :account
end
You don't need to add another class AccountManager, You can add one more relation like this:
class User < ActiveRecord::Base
# user declaration
has_many :account
has_many :managed_accounts, :class_name => 'Account', :primary_key => :account_manager_id
end
class Account < ActiveRecord::Base
belongs_to :user
belongs_to :account_managers, : class_name => :User, :foreign_key => :account_manager_id
end
For this you will need to have account_manager_id in the accounts table.
The main issue I can see here is that a user has_many accounts, but in ur example, an account only has 1 user. Are u planning to have accounts with only 1 person in them?
In relational tables there are 2 main kinds of table designs.
A. One to Many
U have a relationship where one thing has many of another thing, for instance: a Owner has many Cats. In this type of relationship the Cat table can point to the Owner table. Clearly the Owner cannot point to its cats because u would need to have a pointer for each cat. it would be something like
Owners table
cat_1
cat_2
cat_3
thats not convenient at all, since there is a maximum number of cats.
If on the other hand u have
cats table
owner_id
then each owner can have an unlimited amount of cats.
More complex
After some time u get a request, some owners share a cat. u think about it a while and decide a cat can only belong to a max of 2 owners.
so u change the cat table.
cats table
owner_1
owner_2
B. Many to Many
If you want to be able to allow a cat to have any unlimited number of owners, or a owner to have an unlimited number of cats, u will need a third table. This table keeps a link from 1 cat to 1 owner. Each row defines this relationship. This table can be named either using the names of the other 2 tables: cat_owners or since this table defines a relationship u can give it a name that defines this relationship.
In this case the relationship is Ownership, people own cats. Its hard to say how the cats would define the relationship :)
This brings me to answer ur question finally. If u have a table that defines the link between a user and an account, I like the name Membership
Membership
user_id
account_id
but as u just mentioned there are some users in an account who are Managers, u can add this flag to the membership table.
Membership
user_id
account_id
manager (true/false)
u could take it a step beyond that and change manager, to a role column, and then every user can have a different role in every account.
What if each user can have multiple roles in each account? Then u will need more tables
Rails doesnt mean u can skip understanding relational databases structure.
TL;DR: How do I use the ID of the respective parent object in a has_many SQL clause to find child objects?
Long version:
I have the following example code:
class Person < AR::Base
has_many :purchases, -> {
"SELECT * from purchases
WHERE purchase.seller_id = #{id}
OR purchase.buyer_id = #{id}"
}
This was migrated from Rails 3 which worked and looked like
has_many :purchases, :finder_sql => proc { #same SQL as above# }
I want to find all purchases associated with a Person object in one association, no matter whether the person was the one selling the object or buying it.
Update: I corrected the SQL, it was inside out. Sorry! Also: The association only needs to be read-only: I am never going to create records using this association, so using id twice should be OK. But I do want to be able to chain other scopes on it, e.g. #person.purchases.paid.last_5, so creating the sum of two associations in a method does not work (at least it didn't in Rails 3) since it doesn't return an AM::Relation but a simple Array.
When using this above definition in Rails 4.2, I get
> Person.first.purchases
undefined method `id' for #<Person::ActiveRecord_Relation:0x...>
The error is clear, but then how do I solve the problem?
Since this is only an example for much more complicated SQL code being used to express has_many relationships (e.g. multiple JOINS with subselects for performance), the question is:
How do I use the ID of the parent object in a has_many SQL clause?
I don't think your code will work at all. You are defining an association with two foreign keys ... that'd mean that in case you want to create a new Person from a present Purchase, what foreign key is to be used, seller_id or buyer_id? That just don't make sense.
In any case, the error you are getting is clear: you are calling a variable id which is not initialized in the block context of the SQL code.
A better approach to the problem I understand from your question would be to use associations in the following way, and then define a method that gives you all the persons, both buyers and sellers that a product has. Something like this:
class Purchase < ActiveRecord::Base
belongs_to :buyer, class_name: 'Person'
belongs_to :seller, class_name: 'Person'
def persons
ids = (buyer_ids + seller_ids).uniq
Person.where(ids: id)
end
end
class Person < ActiveRecord::Base
has_many :sold_purchases, class_name: 'Purchase', foreign_key: 'buyer_id'
has_many :buyed_purchases, class_name: 'Purchase', foreign_key: 'seller_id'
end
Im my approach, buyer_id and seller_id are purchase's attributes, not person's.
I may have not understood correctly, in that case please clarify.
New in rails here. I have trouble understanding this specific activerecord association. Can someone help me on this. The model looks like this:
class User < ActiveRecord::Base
has_many :client_occurrences,
foreign_key: "client_id",
class_name: "Occurrence"
has_many :requested_occurrences,
foreign_key: "requestor_id",
class_name: "Occurrence"
end
And the one it's associated to is:
class Occurrence < ActiveRecord::Base
belongs_to :template, autosave: true
belongs_to :requestor, class_name: "User"
belongs_to :client, class_name: "User"
end
I just can't seem to understand the associations being portrayed here. Everytime I see the user model, I immediately classify it as an issue because here's how I read the association in the user model:
User has many occurrences alias by client_occurrences and set
client_id as foreign_key
It's an issue for me since the foreign_key is not in the proper table (According to my understanding of the code). In addition, client_id and requestor_id are columns found in the Occurrence table.
Could anyone help?
I'm not sure where your issues are. I would say your reading is correct, namely:
User does have many Occurences (each Occurence points back to
the User)
They are aliased/referenced as client_occurrences from
the perspective of the User The foreign_key is indeed
client_id.
That is, the Occurence table uses client_id to point
to the User
From the point of view of Occurrence:
Each Occurrence belongs to a :client, which means the field name will be client_id (which matches the foreign_key clause in the User model)
The item being pointed to is really a User
One of the things that's confusing, I think, is that the order of the has_many clauses is different from the order of the corresponding belongs_to clauses.
These are the business rules I gather from that:
A User can be associated with an Occurrence as a client
A User can be associated with an Occurrence as a requestor
A User can be associated to many Occurrences
An Occurrence has one requestor User, and one client User
The foreign key is specified in the User model because it's associated to the same model multiple times, otherwise rails would default to using "user_id" as the foreign key in the Occurrence model.
Check this link out for the full details on what all the different ActiveRecord Associations do:
Rails Guides: ActiveRecord Associations