I have two models, User and Request
By definition, A User can have many requests, and each Request has one assigned agent (who can be a different user)
with the base as,
class User < ActiveRecord::Base
has_many :requests
end
But there's a column in Request model, agent_id which has to be linked to User.
So how do I set the relationships the best way for,
1. User has_many requests (with column requests.user_id)
2. Request has_one user(with column requests.agent_id)
Both these on Requests table
This may be what you're looking for.
class User < ActiveRecord::Base
has_many :requests
end
class Request < ActiveRecord::Base
belongs_to :user
belongs_to :agent, class_name: 'User', foreign_key: 'agent_id'
end
You'd use the long form version of the associations. Look them up in the source code to see all the options, but for this example only one extra option needs to be specified since everything else is default.
For user
has_many :requests, foreign key: :agent_id
For request
has_one :user, foreign_key: :agent_id
It should works
class User < ActiveRecord::Base
has_many :requests
end
class Request < ActiveRecord::Base
belongs_to :agent, class_name: 'User'
end
If you want also link User with agent_id:
class User < ActiveRecord::Base
has_many :requests, foreign_key: 'agent_id'
end
The best way to establish Relationships is to follow Rails Naming Conventions.
Rename column 'agent_id' to 'user_id'.
By doing so, you can use
class User < ActiveRecord::Base
has_many :requests
end
class Request < ActiveRecord::Base
belongs_to :user
end
Related
I have a question on a platform I'm developing in Ruby on Rails 5.2.
I have an Owner model which is the owner of properties/property. The owner will post a property so that users (in this case roomates) can share the same property/house/department, etc.
I have Owners and I have Users (both tables are created using devise):
Owner.rb:
class Owner < ApplicationRecord
has_many :properties
end
User.rb:
class User < ApplicationRecord
#Theres nothing here (yet)
end
This is where the magic happens. Property.rb:
class Property < ApplicationRecord
belongs_to :owner
has_many :amenities
has_many :services
accepts_nested_attributes_for :amenities
accepts_nested_attributes_for :services
mount_uploaders :pictures, PropertypictureUploader
validates :amenities, :services, presence: true
scope :latest, -> { order created_at: :desc }
end
How can multiple users share a property? I'm aware that it will have a many-to-many association but I'm a bit confused how to connect these relationships so when the owner posts a property it will display something like:
Property available for: 3 users
And then begin to limit users until it completes the amount of users available.
This sounds like your average many to many assocation:
class User < ApplicationRecord
has_many :tenancies, foreign_key: :tenant_id
has_many :properties, through: :tenancies
end
class Tenancy < ApplicationRecord
belongs_to :tenant, class_name: 'User'
belongs_to :property
end
class Property < ApplicationRecord
has_many :tenancies
has_many :tenants, through: :tenancies
def availablity
# or whatever attribute you have that defines the maximum number
max_tenants - tenancies.count
end
end
You can restrict the number of tenants with a custom validation.
You can use a join table, called users_properties. This table will have a property_id and user_id. You'll then have the following in your properties model:
has_many :users_properties
has_many :users, through: :users_properties
Read more about it here https://guides.rubyonrails.org/association_basics.html
I have three models:
class User < ApplicationRecord
has_many :game_accounts
has_many :favorite_game_accounts, through: :game_account_favorites, source: :game_account
end
class GameAccount < ApplicationRecord
belongs_to :user
has_many :favorite_users, through: :game_account_favorites, source: :user
end
class GameAccountFavorite < ApplicationRecord
belongs_to :user
belongs_to :game_account
validates_presence_of :user, :game_account
validates_uniqueness_of :user, scope: :game_account_id
end
This means that User can have his own GameAccounts and other Users can add them to favorites.
I have added scope in order to prevent one user to have multiple favorites of the same GameAccount. However, there is one problem. User can add to favorite his own GameAccount. How to prevent user adding his own GameAccount to favorites?
I'm not sure that there is any built-in Rails validation for you case, so I'd suggest writing your own custom one.
In your particular case, you can verify on GameAccountFavorite instance, that game_account.user_id isn't equal to user.id.
There's plenty of ways of performing custom validation in Rails
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.
The Ruby on Rails app I am working on allows users to create and share agendas with other users.
In addition, we must be able to:
Display a list of agendas for each user, on his profile
Display a list of users associated with an agenda, on the agenda's page
When sharing an agenda with another user, define a role for this user, and display the role of this user on the list mentioned right above
I was going to go with a has_and_belongs_to_many association between the user and the agenda models, like that:
class User < ActiveRecord::Base
has_and_belongs_to_many :agendas
end
class Agenda < ActiveRecord::Base
has_and_belongs_to_many :users
end
But then I wondered whether this would let me get and display the #user.agenda.user.role list of roles on the given agenda page of a given user.
And I thought I should probably go with a has_many :through association instead, such as:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
And although I was pretty comfortable about the idea of a user having several roles (one for each agenda), I am not sure about the idea of an agenda having several roles (one for each user?).
Finally, to add to the confusion, I read about the polymorphic association and thought it could also be a viable solution, if done this way for instance:
class Role < ActiveRecord::Base
belongs_to :definition, polymorphic: true
end
class User < ActiveRecord::Base
has_many :roles, as: :definition
end
class Agenda < ActiveRecord::Base
has_many :roles, as: :definition
end
Does any of the above solutions sound right for the situation?
UPDATE: Doing some research, I stumbled upon this article (from 2012) explaining that has_many :through was a "smarter" choice than has_and_belongs_to_many. In my case, I am still not sure about the fact that an agenda would have many roles.
UPDATE 2: As suggested in the comments by #engineersmnkyn, a way of solving this would be to go with two join tables. I tried to implement the following code:
class User < ActiveRecord::Base
has_many :agendas, through: :jointable
end
class Agenda < ActiveRecord::Base
end
class Role < ActiveRecord::Base
end
class Jointable < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :agendaroles through :jointable2
end
class Jointable2 < ActiveRecord::Base
belongs_to :roles
belongs_to :useragenda
end
I am not sure about the syntax though. Am I on the right track? And how should I define the Agenda and the Role models?
UPDATE 3: What if I went with something like:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
and then, in the migration file, go with something like:
class CreateRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.belongs_to :user, index: true
t.belongs_to :agenda, index: true
t.string :privilege
t.timestamps
end
end
end
Would I be able to call #user.agenda.privilege to get the privilege ("role" of creator, editor or viewer) of a given user for a given agenda?
Conversely, would I be able to call #agenda.user.privilege ?
Okay I will preface by saying I have not tested this but I think one of these 2 choices should work well for you.
Also if these join tables will never need functionality besides a relationship then has_and_belongs_to_many would be fine and more concise.
Basic Rails rule of thumb:
If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.
First using your example (http://repl.it/tNS):
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda:agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user_agenda
end
This uses a join table to hold the relationship of User <=> Agenda and then a table to join UserAgenda => Role.
The Second Option is to use a join table to hold the relationship of User <=> Agenda and another join table to handle the relationship of User <=> Agenda <=> Role. This option will take a bit more set up from a CRUD standpoint for things like validating if the user is a user for that Agenda but allows a little flexibility.
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda: agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user
belongs_to :agenda
end
I know this is a long answer but I wanted to show you more than 1 way to solve the problem in this case. Hope it helps
In my app a User can Post something to his timeline and Tag other's users in his post (something like facebook). In my model I have to know who was tagged in which post and who did tag (always the post's owner). I've found something similar here with hashtags model, but I couldn't get the expected outcome with this.
My first question is: the approach below is right? If so, how could I validate the existence of the user before the association is created?
class User < ActiveRecord::Base
has_many :posts
has_many :tagger_users, class_name: "Tag", foreign_key: "tagger_id"
has_many :tagged_users, class_name: "Tag", foreign_key: "tagged_id"
class Post < ActiveRecord::Base
has_many :tags
class Tag < ActiveRecord::Base
belongs_to :tagger_user
belongs_to :tagged_user
belongs_to :post
validates_presence_of :tagger_user, :tagged_user # This always return ["Tagger post can't be blank", "Tagged post can't be blank"] even when the users are correctly set
I think the correct thing would be having a Tag which belongs to two users, the tagged and the tag. Then the post can have a owner, and a list of tagged users using has_many :through
class User < ActiveRecord::Base
has_many :posts
class Post < ActiveRecord::Base
has_many :users, :through: :tags
belongs_to :user
class Tag < ActiveRecord::Base
belongs_to :tagger_user, class_name: user
belongs_to :tagged_user, class_name: :user
validates_presence_of :tagger_user
validates_presence_of :tagged_user
About validating check this answer. If the ends are valid, they should be automatically persisted.