How to implement ancestry for this specific situation - ruby-on-rails

We have a Real-Estate app in which the User can be a Renter or Landlord(Owner). Renters can search for specific houses listed by the Owners. Renters can also add other persons(friends or acquaintances who are staying with that specific renter). In the app we treat them as Coapplicants.
Models
# user.rb
class User < ActiveRecord::Base
has_one :renter
has_one :owner
end
# renter.rb
class Renter < ActiveRecord::Base
belongs_to :user
has_many :coapplicants
end
# coapplicant.rb
class Coapplicant < ActiveRecord::Base
belongs_to :renter
end
Now as to increase the number of users for the app,we implemented a mailing system which sends an Welcome Mail(when the Renter adds a Coapplicant) to signup as a User.And that Coapplicant can choose to be Renter and can add many Coapplicants too. And the process goes on again resulting in increasing the users.
It's like a tree structure and now I want to set-up a perfect database relations(associations) to track the users flowing in and through which renter/coapplicant they are coming.
Now the Current Model structure(not yet developed) looks like this
# user.rb
class User < ActiveRecord::Base
has_one :renter
has_one :owner
end
# renter.rb
class Renter < ActiveRecord::Base
belongs_to :user
has_many :coapplicants
has_many :coapp_renters,
:through => :coapplicants
has_many :inverse_coapplicants,
:class_name => "Coapplicant",
:foreign_key => "coapp_renter_id"
has_many :inverse_coapp_renters,
:through => :inverse_coapplicants,
:source => :renter
end
# coapplicant.rb
class Coapplicant < ActiveRecord::Base
belongs_to :renter
belongs_to :coapp_renter,
:class_name => "Renter"
end
I guess i messed up things a bit. Which database-relationships(associations) would be the best for my current situation.
Can someone throw some light on this please.I'm thinking about using the ancestry gem but how to implement to my current situation.

I've found that sometimes even a small change in perspective when designing your associations can make them flow a lot more naturally.
You have focused exclusively on person entities; User.find(1).renter for example isn't very intuitive, since both models depict essentially the same person.
Instead of trying to model what people are, I would try to model what they have. In this case, instead of a User having a Renter, let them have many Rentals:
class User < ActiveRecord::Base
has_many :rentals,
foreign_key: 'renter_id'
end
class Rental
belongs_to :renter,
class_name: 'User'
belongs_to :property
end
I assume here that you have a model Property that stands for what is being rented - leave that out if it doesn't exist.
It's the same thing for owners. A User becomes an owner just by having Ownerships:
class User < ActiveRecord::Base
has_many :ownerships,
foreign_key: 'owner_id'
end
class Ownership
belongs_to :owner,
class_name: 'User'
belongs_to :property
end
A co-application is slightly different in that it belongs to a Rental:
class CoApplication
belongs_to :co_applicant,
class_name: 'User'
belongs_to :rental
end
class Rental
has_many :co_applications
end
class User < ActiveRecord::Base
has_many :co_applications,
foreign_key: 'co_applicant_id'
has_many :received_co_applications,
through: :rentals,
source: :co_applications
end
Now your Users can be owners, renters, co-applicants - all at the same time. And these associations allow you to capture everything that happened - who signed on whom through what is just a matter of chronological order.
From here on it's a matter of nesting your has_many :through associations to get whatever you want.
Want to know the properties a landlord owns?
has_many :owned_properties,
through: :ownerships,
source: :property
The rentals to her properties?
has_many :leases,
through: :owned_properties,
source: :rentals
The people who rented her properties?
has_many :renters,
through: :leases,
source: :renter
Same thing with co-applications. Want to know who co-applied with a user?
has_many :co_applicants,
through: :received_co_applications,
source: :co_applicant

I would refactor your code and make the co-applicants just a renter that is a child of another renter
in your renter model you have to add a "parent_id" to know whom the co-applicants belongs to.
now in your model you can do something like
#renter.rb
class Renter < ActiveRecord::Base
belongs_to :user
has_many :children, :class_name => "Renter"
belongs_to :parent, :class_name => "Renter"
end
# Example calls
Renter.first.children
Renter.first.parent
I hope this helps

Create a table called Relationship (or something) with two foreign_ids concerning what you want the User and Renter to be able to do with one another (example to be able to "Follow" one another => Follower_id and Following_id). Define methods in your Models related to those ids and then call those methods in your views to display the relations.

Related

Rails object both belongs_to and has_one

I'm having a trouble with grasping a proper relationship between two Rails/ActiveRecord classes.
I have a User, which can both create a Slip and simultaneously be an addressee of another slip. Each user can create any number of slips but only one user as the addressee of a given slip.
From the db perspective I have two integer (key) columns for 'user_id' (author) and 'addressee' in the slips table and no reference on the users table.
This is my current approach which is not working at all:
class User < ApplicationRecord
has_many :slips
belongs_to :slips, :foreign_key => 'addressee'
end
class Slip < ApplicationRecord
belongs_to :user
has_one :addressee, :through => :user
end
Please direct me to the proper way of binding these objects.
Thanks and have a nice day!
It should look something like this (the second one could just be called 'slip' but I've called it 'addressor_slip' to avoid confusion):
class User < ApplicationRecord
has_many :slips
has_one :addressor_slip, :class_name=> 'Slip', :foreign_key => 'addressee'
end
class Slip < ApplicationRecord
belongs_to :user
belongs_to :addressee, :class_name=> 'User', :foreign_key => 'addressee'
end
You could also create an association from User to User through :addressor_slip
Look at many to many relationships here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
You're probably looking for has_and_belongs_to_many.

Active Record association has_many with multiple foreign keys

I'm trying to set up a referral model. A referral contains a user who is referred, a user who does the referring, and a doctor
class User < ActiveRecord::Base
has_many :referrals
belongs_to :profile, polymorphic: true
end
class Referral < ActiveRecord::Base
belongs_to :user
belongs_to :referrer, :class_name => "User"
belongs_to :doctor, :class_name => "User"
end
I'm able to create the generic has_many :referrals to see doctors that have been referred to the user however I'd also like to see the doctors that you've referred to others (using the referrer column).
I've tried has_many :doctors_referred, primary_key: "referrer_id" and has_many :doctors_referred, through: :referrals ,source: "referrer" with no luck. How can I see which doctors a user has referred?
# mostly irrelevant
class PatientProfile < ActiveRecord::Base
has_one :user, as: :profile
end
class DoctorProfile < ActiveRecord::Base
has_one :user, as: :profile
end
My first attempt would be this:
class User < ActiveRecord::Base
has_many :referrals_as_referrer, source: :referred
has_many :referrals_as_referree, source: :user
has_many :doctors_as_referrer, through: :referrals_as_referrer
has_many :doctors_as_referree, through: :referrals_as_referree
end
The issue here is that saying has_many :referrals isn't enough because you can have a referral where you were the referrer or one where you were the referree. With this you can type user.referrals_as_referrer which will give a list of referrals where user is the referrer. You can also write user.doctors_as_referrer which will go through the previous association and retrieve a list of users that represent doctors which were referred by a referral in the user.referrals_as_referrer list.
I haven't tested this and I might be wrong, but let's iterate once you try it out.

Rails belongs_to_many

I'm a beginner in Rails and I have a problem with ActiveRecords associations.
I'm creating simple car rental service and I made the following associations:
class Client < ActiveRecord::Base
has_many :rentals
has_many :bookings
has_many :cars, :through => :rentals
has_many :cars, :through => :bookings
end
class Rental < ActiveRecord::Base
belongs_to :client, dependent: :destroy
has_one :car
end
class Booking < ActiveRecord::Base
belongs_to :client, dependent: :destroy
has_one :car
end
What I need is to have a car belonging to many bookings and rentals while every booking and rental can have only one car assigned.
class Car < ActiveRecord::Base
# belongs_to_many :bookings
# belongs_to_many :rentals
end
How should I do that?
If a car can have many bookings/rentals, but a booking/rental can only have one car, you're looking at a classic belongs_to/has_many situation. It looks like you're being tripped up by the distinction between belongs_to and has_one -- it's not a grammatical one, but a matter of where the foreign key column is located in your database.
belongs_to: "I am related to exactly one of these, and I have the foreign key."
has_one: "I am related to exactly one of these, and it has the foreign key."
has_many: "I am related to many of these, and they have the foreign key."
Note that has_one and has_many both imply there's a belongs_to on the other model, since that's the only option where "this" model has the foreign key. Note also that this means has_one should only be used when you have a one-to-one relationship, not a one-to-many.
Taking this into consideration, I would replace the has_one :car with belongs_to :car in both your Rental and Booking models, and place has_many :bookings and has_many :rentals in your Car model. Also ensure that your rentals and bookings tables have a car_id column; there should be no rental- or booking-related columns in your cars table.
Yes, there is a "belongs_to_many" in Rails, sort of. It's a little more work and you can't use generators with it. It's called a polymorphic association.
Even though you could make a car have many bookings & rentals, you could associate the car by making it belong to a polymorph such as rentable_vehicle. Your code would look like this
class Car < ActiveRecord::Base
belongs_to :rentable_vehicle, polymorphic: true
end
class Rental < ActiveRecord::Base
belongs_to :client, dependent: :destroy
has_many :cars, as: :rentable_vehicle
end
class Booking < ActiveRecord::Base
belongs_to :client, dependent: :destroy
has_many :cars, as: :rentable_vehicle
end
You can't do belongs_to_many. The closest you can really get is has_and_belongs_to_many, but I'm not sure that's what you want here - unless you can have multiple cars per rental/booking. Check out the guide for a full explanation.
I'd change it up like this:
class Rental < ActiveRecord::Base
belongs_to :client, dependent: :destroy
belongs_to :car
end
class Booking < ActiveRecord::Base
belongs_to :client, dependent: :destroy
belongs_to :car
end
class Car < ActiveRecord::Base
has_many :bookings
has_many :rentals
end
Also, I don't know how your rentals relate to bookings, but my immediate thought is that there should be some relationship between the two, because you probably can't have a rental without booking it, right?

How do I assign items that belong to one half of "has many :through" with the other half of the association?

I'm trying to model my database in Ruby and can't figure out how to do it.
This is what I have so far:
class Course < ActiveRecord::Base
has_many :enrolled_ins
has_many :users, :through => :enrolled_ins
has_many :events, :dependent => :destroy
end
class User < ActiveRecord::Base
has_many :enrolled_ins
has_many :courses, :through => :enrolled_ins
end
class EnrolledIn < ActiveRecord::Base
belongs_to :users
belongs_to :courses
end
class Event < ActiveRecord::Base
belongs_to :courses
end
I want to add that when a user picks a course, they can select the different events that they want with that course, and those are assigned to them instead of them getting all the events.
I would add a UserEvents join. When you add a course, you would see a list of available events. Assuming you have a form with checkboxes, you would create the UserEvent records. I don't think you would need all 3 ID values (user, event, course). Course is just a way to group the various events.
class UserEvent < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
I'd also add a dependent destroy on user and on event do destroy the join records if either side is removed.

has_many :through relationships explained

I'm new to Rails and have some doubts about the kind of relationship do I need to use. Here is the case.
I have two models Offer and User, a user could belong to to many offers and offers can have many user. Also the users create the offers.
I think I have to use a has_many :through ralationship. For example I've created another model "Applicant". Applicant belongs_to user and belongs_to offer. But how is the relationship from the user and offer model? For example:
User Model
has_many :offer, :through => :applicant
Offer Model
has_many :user, :through => :applicant
My doubt is because I already have this two relationship
User Model
has_many :offers, :dependent => :destroy
Offer Model
belongs_to :user
After solve this, I guest I have to save the record in the applicant model from the applicanst_controller, right?
Thanks in advance
What you have described is a many-to-many relationship using a join table. You're actually pretty close but you just need to remove the has_many :offers, :dependent => :destroy from your user model and the blongs_to :user in your offer model. It should look something like this:
class User < ActiveRecord::Base
has_many :offers, :through => :applicants
end
class Applicant < ActiveRecord::Base
belongs_to :users
belongs_to :offers
end
class Offer < ActiveRecord::Base
has_many :users, :through => :applicants
end
You don't have to worry about the dependent destroy part as associations are automatically removed as the corresponding objects are removed. With a many to many association it doesn't really matter how you go about building the relationship. Either of the following will work:
#user.offers << #offer
#offers.users << #user
If you don't need to store any information specific to your applicant join table (e.g., time stamps, descriptions) you might instead want to look at a has_and_belongs_to_many relationship. Check out choosing between has_many_through and has_and_belongs_to_many for reference.
Edit
Heres the code for a HABTM relationship:
class User < ActiveRecord::Base
has_and_belongs_to_many :offers
end
class Offer < ActiveRecord::Base
has_and_belongs_to_many :users
end

Resources