I'm modeling a lessons table, the lesson belongs to a user, the teacher and creator of the lesson, and also, the lesson can have many students, which are also users.
So it would be something like this
class Lesson < ActiveRecord::Base
belongs_to :user
has_many :users
end
I'd like to call the first user teacher, and the collection of users students, I've read the documentation at http://guides.rubyonrails.org/association_basics.html but I can't quite find what I want.
This should have what you want: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to
I think you want the class_name option:
class Lesson < ActiveRecord::Base
belongs_to :teacher, class_name: "User"
has_many :students, class_name: "User"
end
In your current code, all users could be the "owner" (teacher) of a lesson, instead you should have two additional classes "student" and "teacher" both having a 1:1 relation to the "user" class.
This would fit better:
class Teacher < ActiveRecord::Base
has_one :user
end
class Student < ActiveRecord::Base
has_one :user
end
class Lesson < ActiveRecord::Base
belongs_to :teacher
has_many :students
end
Related
I have three models:
Company;
Investor;
Broker.
in real world each investor can invest in many companies, but in some he/she can invest with broker assistance.
I made it through joint table.
def change
create_join_table :companies, :investors do |t|
t.references :broker, index: true, optional: true
end
end
class Company < ApplicationRecord
has_and_belongs_to_many :investors
end
class Investor < ApplicationRecord
has_and_belongs_to_many :companies
end
class Broker < < ApplicationRecord
has_many :companies
end
How should I configure my models/migrations to have next information:
Company.first.investors.first.broker
broker is not belongs to investor, in each company/investor pair can be different broker.
Use has_many through associations and add the broker on the join model. After adding the proper migrations your models will look like this:
class Company < ApplicationRecord
has_many :company_investors
has_many :investors, through: :company_investors
end
class Investor < ApplicationRecord
has_many :company_investors
has_many :companies, through: :company_investors
end
class Broker < ApplicationRecord
has_many :company_investors
has_many :companies, through: :company_investors
end
class CompanyInvestor < ApplicationRecord
belongs_to :broker
belongs_to :investor
belongs_to :company
end
With this models, you can add Investor to Company associations with or without Broker, and also discriminate them. I also recommend naming the join model (which in my code I named CompanyInvestor) a more significant name, like Investment
I'm having the following problem while trying to model my application, it's basically a functionality to handle bills with multiple people, like sharing the rent or any other similar stuff, the deal is:
I have a user model and a billing model but can't find out how to build the associations.
A user has_many billings and billings belongs_to user but, also the billing has_many users, e.g. Tom registers a bill that is meant to be shared by Tom himself, Betty and Bob.
So that makes Tom the creditor and the other two become debtors in the billing.
I'm kinda lost at this point, how to consolidate these associations, dunno if any more information is needed or if it's clear enough, but will appreciate any help and update with any other information needed.
Thanks in advance,
---EDIT---
I've come to the following approach:
Class User < ActiveRecord::Base
has_many :billings, foreign_key: "creditor_id", dependent: :destroy
end
Class Billing < ActiveRecord::Base
belongs_to :creditor, class_name: "User"
has_many :debts, dependent: :destroy
end
Class Debt < ActiveRecord::Base
belongs_to :billing
has_one :user
end
I also tried to graphically model it for better understanding here: imgur
Would that all be correct?
Don't be afraid to use the options available to you in ActiveRecord. If your model naming is getting cluttered (Billing belongs to a User and has_many Users) then be more specific with the association labels and sort the links with options. The Rails Associations Guide is easy to Google and covers pretty much everything.
class User < ActiveRecord::Base
has_many :billings, :foreign_key => 'creditor_id'
has_many :debts, :through => :debtor_users, :source => :billing
end
class Billing < ActiveRecord::Base
belongs_to :creditor, :class_name => 'User'
has_many :debtors, :through => :debtor_users, :source => :user
end
class DebtorUser < ActiveRecord::Base
belongs_to :billing
belongs_to :user
end
You can extend the Billing model to have multiple creditors also simply by converting the belongs_to association into a has_many :through association following the same pattern as debtors just with a different join model (say CreditorUser).
Is it possible to access objects more than one model away?
For example let's say I have
class Contact <ActiveRecord:Base
has_many :interactions
end
class Interaction <ActiveRecord:Base
belongs_to :contact
belongs_to :course_presentation
end
class CoursePresentation <ActiveRecord:Base
has_many: interactions
belongs_to :course
end
class Course <ActiveRecord:Base
has_many :course_presentations
end
Right now I know I could write a through relationship via contacts to course presentations and then get all the course related to all the course presentations or I could do
contact.interactions.map{ |i| i.course_presentation.course }
I would like to be able to pull courses related to a contact directly so ... e.g.
contact.courses
Is this possible?
Yes, I believe so. Just add the following:
class Contact < ActiveRecord::Base
has_many :interactions
has_many :course_presentations, through: :interactions
has_many :courses, through: :course_presentations
end
I'm on rails 3.0 and trying to figure out what would be the proper way to setup a belong_to :through relationship (which) I know is not possible. Here's an example:
class ParentCompany < ActiveRecord::Base
has_many :subsidiaries
has_many :employees, :through => :subsidiaries
end
class Subsidiary < ActiveRecord::Base
belongs_to :parent_company
has_many :employees
end
class Employee < ActiveRecord::Base
belongs_to :subsidiary
belongs_to :parent_company, :through :subsidiary # <-- I know this is invalid
end
I know I can solve it by doing:
class Employee < ActiveRecord::Base
def parent_company
subsidiary.parent_company
end
end
However, I'd like to know if I can do the above via associations.
You can use delegate to accomplish this without using an association
class Employee < ActiveRecord::Base
belongs_to :subsidiary
delegate :parent_company, to: :subsidiary
end
There are Things in Places which I'm looking to find. One Thing could be in many different Places, and many Things can be in one Place.
class Thing < ActiveRecord::Base
has_and_belongs_to_many :places
end
class Place < ActiveRecord::Base
has_and_belongs_to_many :things
end
I want to record the Finds of my Users so that I know where they found what.
class Find < ActiveRecord::Base
belongs_to :user
belongs_to :places_thing # Is this depluralization correct?
end
class User < ActiveRecord::Base
has_many :finds
# Now, how can I link in the Things the user has found? Like this?
has_many :found_things_in_places, :class_name => :places_things, :through => :finds
has_many :things, :through => :thought_things_in_places
end
Does this seem right? is it efficient? Thanks.
I think you were on the right track, the big change I'd make is that rather than having a join table (places_things) you should make it a proper model. I decided to call this an existence.
The data only exists in one place, so it's properly normalized. These relationships are clear and will be easy to manage. I think it's efficient.
class Place < ActiveRecord::Base
has_many :existences
has_many :things, :through => :existences
end
class Thing < ActiveRecord::Base
has_many :existences
has_many :places, :through => :existences
end
class Existence < ActiveRecord::Base
belongs_to :place
belongs_to :thing
end
class Find < ActiveRecord::Base
belongs_to :user
belongs_to :existence
end
class User < ActiveRecord::Base
has_many :finds
has_many :existences, :through => :finds
has_many :things, :through => :existences
end
You'll need rails 3.1 to do the nested has many through's like we did in User.
BTW the correct association declaration should be: belongs_to :places_things