Making two associations to same model column in Rails - ruby-on-rails

I'm pretty new to rails. I'm trying to setup associations to another model in Rails.
I have a User model with columns: id, user_name, email
Now I am trying to create another model Expense which has associations to the user model. The purpose of this model is to create an expense and associate the expense with two different users from the same model User. The association to the second user is to split the amount between the two users.
This is what I'm intending to do while creating the model Expense:
$ rails generate model Expense amount:decimal user:references split_with:references
Now how do I associate split_with to the User model, since both references associate to the same User model's id of two users?

You can refer to the same model two different ways:
class Expense < ActiveRecord::Base
belongs_to :user
belongs_to :approving_user,
class_name: 'User'
end
This would require columns user_id and approving_user_id to be present. You can always adjust the generated migration and model code to match this.
As always be sure that index: true are set on these columns.

Related

act_as_tenant with child records

I am working on a Rails project with act_as_tenant. At the moment, I have a model that looks like this:
class Portfolio < ApplicationRecord
acts_as_tenant :organization
has_many :holdings
end
Additionally, I have this Holding model:
class Holding < ApplicationRecord
belongs_to :portfolio
end
act_as_tenant is working correctly for the Portfolio model. That is, if I am logged in as an organization that does not match the Portfolio's organization, that Portfolio won't exist in the database.
However, as I am logged in as a different organization, I can still access the Holding. But when I try to do holding.portfolio, I get nil.
Is there a way to extend this sort of act_as_tenant logic so that all child models of a parent model will automatically be scoped by tenant as well?
Reading the documentation for acts_as_tenant:
Row-level multitenancy each model must have a tenant ID column on it. This makes it easy to filter records for each tenant using your standard database columns and indexes. ActsAsTenant uses row-level multitenancy.
What this implies that also the holding model should have acts_as_tenant :organization and have a foreign key to organization. This should be the case also for other records you plan to add that are dependent on acts_as_tenant

Ruby on Rails, User Models and Active Admin query

I am using Active Admin in my application.
The application has a Users model (Devise) but I have 3 user groups - parents, teachers and students. Each has their own model.
e.g
student.rb
belongs_to :user
user.rb
has_one :student
parent.rb
belongs_to :user
user.rb
has_one :parent
What I am trying to do here is store the attributes that would be the same across the user groups in the Users model so "first_name, last_name, email" etc and then using the individual user models to store attributes that are unique to each user group. I am using a one to one relationship between the main users table and the three user group tables.
Here (note I have not displayed all attributes in the user group tables):
The problem is this is not working out so well with Active Admin. In the view I have to create a user and then assign a parent and a student in different views. I would like to have a single form where, for example, a student's user record can be put in with the attributes from the main Users table as well as their unique attributes in the students table without having to go to multiple model views to complete records. It's too convoluted.
Is there a way to render the inputs from different models in the one view? i.e in students have "first name", "last name"...from the Users table along with the inputs unique to a student?
If you were taking the approach I am taking here what method would you follow? I'm not even sure I am doing the associations right. In fact i'm not even sure this is the most efficient way to do this.
I am using enums to assign the roles.
Would appreciate any guidance here. Thanks.
Students, Guardians, and Teachers are all a type of User. Why not consolidate them into a single type and use inheritance to represent them as a common type?
class User < ActiveRecord::Base
# ...
end
class Teacher < User
# ...
end
class Guardian < User
# ...
end
class Student < User
# ...
end
You'll need to add a type column via a migration, and also write a task to merge them into a common table, but it will likely be worth the effort.
See STI in Rails: http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html.
EDIT:
If you don't want to go the STI route, you'll have to use nested attributes
class User < ActiveRecord::Base
accepts_nested_attributes_for :teacher
accepts_nested_attributes_for :guardian
accepts_nested_attributes_for :student
end
Then add a custom form in admin/user.rb ():
ActiveAdmin.register User do
form do |f|
f.inputs "User Inputs" do
# ...
f.input :email
# ...
end
f.inputs "Guardian Attributes", for: [:guardian, f.object.guardian || Guardian.new] do |g|
g.input :mobile_no
end
# Repeat for teacher, Student, etc...
end
end
If you're using strong parameters, make sure you whitelist the appropriate params for User, guardian_attributes, etc.
In my opinion, the nesting here is pretty ugly and having this normalized schema is going to be difficult to maintain and query.

Rails 3. How to setup User model to act as different roles?

I setup roles for the User model, for now, I just have a role string column for the users table. The value could be admin, salesperson, instructor or student.
Now I have a ScheduledSession model that an Instructor is supposed to teach. I have an instructor_id column, which is supposed to have an id from the users table (an user with a role of instructor).
So how can I setup the association in the models? in the User model is doesn't seem right to add has_many :scheduled_sessions because if the role is a salesperson or an admin, it just doesn't feel right. or setup something like belongs_to :user, :as instructor in the ScheduledSession model, but I get error Unknown key :as.
How would you set this up?
You want to set up your belongs_to slightly differently in the ScheduledSession model.
belongs_to :instructor, :class_name => 'User, :foreign_key => 'user_id'
This allows you to refer to the instructor of a ScheduledSession object and have it point to an entity in the User table.
There's no way around having a has_many relationship on your User model if you want to pursue a role based User with each user having a single role. Without it, you'll have no mechanism to retrieve the scheduled_sessions associated with a user.
An alternative might be to use Single Table inheritance here, which would allow you to create Admin users who don't have SchededSessions, but Instructors who do. You'll still store all of these in the same table, but ActiveRecord will make it easier for you to compartmentalize them.

How can use rails polymorphic for objects that actually have fields?

Let's say I have a User model and I want to have different user roles. In a single application, you can simple store the role a string, or as another model and that's fine.
But what if you want to store more associations for the individual models? For example, let's say Admins contain links to collections and belongs to many collections that regular users should not be associated to? In fact, other users will be linked to a whole other set of models that Admins do not have.
Do we put all of the associations in the User object and just ignore them based on the type of the user? Or do we start subclassing User (like in Hibernate) to only contain the associations and model logic for that user type?
What is the way to do this in rails? Thanks!
I would suggest using Rails Single Table Inheritance. Essentially, you'll have a users table in your database, and a root User model. Multiple models (one for each "role") can inherit from User, and have their own associations:
# Regular users have no associations
class User < ActiveRecord::Base
end
# Admins have collections and notes
class Admin < User
has_many :collections
has_many :notes
end
# Editors only have notes
class Editor < User
has_many :notes
end

What should I do to make a Polymorphic Relationships in RoR?

I have a user table, and have a role column, that identify their role. Now, I want to add a "Student" table, that have the student's student number, and I also want to add a "Teacher", to store the teacher's salary.
Both the Student and Teacher are the subclass of User. Now, I added a role column already in the User table, "T" = Teacher, and "S" = Student. Now, I want to add "Student" and "Teacher" in the database. What should I do? Generate scaffold or migration only? Also, it is necessary to modify my models? or I just need to modify the controller only??
Thank you.
This sounds more like a job for Rails' single table inheritance. It's really easy to use. Instead of using a separate table to store roles. Inherit your student and teacher models from User.
for example:
User < ActiveRecord::Base; ... end
Student < User; ... end
Teacher < User; ... end
Rails automatically creates a type column and stores the class there.
User.all will return all users Student.all will return users where the type is matches Student and Teacher.all will do the same for all teachers.
You can read more about single table inheritance at the ActiveRecord documentation, and here.
As nuclearsandwich said, this is a situation that calls for rails STI (single table inheritance), not polymorphic associations.
Just to highlight the difference:
1) Singe table inheritance is used when you have different models that are very similar to each other with minor differences. STI lumps all models in the same database table, with fields (columns) for all the models that use this table. There is also a "type" field which indicates which model this record belongs to.
Your case is a perfect example of STI. You have user, student, and teacher models, they share a lot of common fields and functionality, you just want an extra field for the student and the teacher.
2) Polymorphic association is used when you have a model that will be associated with different models. For example, imagine you have an "Address" model. Also you have a "Company" and a "User" model, both of which can have an address.
In your Address model, you can specify
belongs_to :user
belongs_to :company
And then make sure if the address belongs to a company not to call address.user and vice-versa. However, a better way to do it would be through a polymorphic association. In your address model you do
belongs_to :addressable, :polymorphic => true
and in your user and company model you add
has_one :address, :as => :addressable
This allows the address model to polymorph (literally: transform into many) its association, and be connected with multiple different models through a single association.

Resources