Ruby-newbie Active Record query / model association - ruby-on-rails-3

Here is roughly what I have:
I have many companies that has many user through roles:
class Company < ActiveRecord::Base
has_many :roles, :dependent => :destroy
has_many :users, :through => :roles
end
and many users which can have many companies through roles:
class User < ActiveRecord::Base
has_many :roles, :dependent => :destroy
has_many :comapnies, :through => :roles
end
and many roles that bind the two together:
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
The idea here is that a user can sign-in through a common email username and then have privileges assigned to each company. Role has a user_id and company_id keys along with a privilege column 'user_role' (i.e. guest, user, admin etc.).
Here is where being ruby-newbie fails me. When my user logs in I want to query which companies they have privileges on and switch that on the fly with a menu drop down. So they login and are active in 'Company A' and then they can switch to 'Company B'. When they switch the company_id is stored in a session variable (I already have their user_id stored with a functioning authentication system).
What is the best way to query this? I have a user_id and I want to retrieve a list of the company_id, company_name, 'user_role' etc. then use this to generate a pop-down list.
I have been playing with the console trying Role.Company.etc.etc but can't seem to figure this out. When I was doing this in PHP / MySQL before it would have been a complex join query. I am sure it's easier in Rails I jet can't seem to figure it out.
Any help would be appreciated.
Thanks,
Dan

You can get all of the companies a user has access to (for any role) via current_user.companies.uniq. The uniq part just ensures you don't have duplicate companies in the list (in the case a user has more than one role for a single company).

Thanks for everyones feedback. This got me looking at includes and joins again. I ended up looking at http://railscasts.com/episodes/181-include-vs-joins and the Rails API docs and cobbled together this:
Role.includes(:company).where(:user_id => session[:user_id])
I then loop through #role and I can pull role.role_name and role.company.name etc. Starting the query with the User.find(session[:user_id]) was complicating it.

Related

SQL relations in Rails. Trying to create two different references for one table relationship. Very confusing situation

I have a DB schema where a shipment belongs_to two users even though the relation is between model to model.
The shipment can have a receiver_id and a sender_id. Both the receiver & sender are two different records in the same table (the user model).
I was wondering how can I establish a relationship in my rails backend for a shipment to belong_to a record where the user is the sender as well as another record in the same DB where the user is the receiver.
I'v been thinking for ages how to do it, and its very hard to come up with a solution. The only solution I have is to destroy the existing User model, and create two different models: a receiver & a sender. Or is there another solution for this? I've attached my DB schema in this thread.
Any help would much appreciated. Thanks in advance!
DB Schema
class Shipment < ApplicationRecord
belongs_to :sender, :class_name => "User"
belongs_to :recipient, :class_name => "User"
end
class User < ApplicationRecord
has_many :sent_shipments, :class_name => "Shipment", foreign_key: 'sender_id'
has_many :received_shipments, :class_name => "Shipment", foreign_key: 'recipient_id'
end

Is it okay to reference a third table in a many-to-many join table?

I am designing a relational database for projects and tasks. I want projects and tasks to be able to be classified or grouped by category.
If a project is shared by two or more users, I want each user to be able to categorize the project separately. Additionally, I want users to be able to share entire categories with each other, including all projects and tasks within that category. Therefore, here is the schema that I have come up with in terms of a basic ERD:
Here are my main models in Rails:
class User < ActiveRecord::Base
has_many :user_projects
has_many :user_categories
has_many :projects, :through => :user_projects
has_many :categories, :through => :user_categories
end
class Project < ActiveRecord::Base
has_many :user_projects
has_many :users, :through => :user_projects
has_many :tasks, :as => :taskable
end
class Task < ActiveRecord::Base
belongs_to :taskable, :polymorphic => true
end
class Category < ActiveRecord::Base
has_many :user_categories
has_many :users, :through => :user_categories
has_many :tasks, :as => :taskable
end
Is it okay to include a category_id foreign key in the User_Project join (junction) table like this? Also, do you see any problems with this schema in general? Any help will be greatly appreciated.
Since you asked if we saw any problems with the schema in general, ...,
The relationship between tasks and projects is not clear. If it's the taskable_id, that's a strange column name. Why not go with project_id?
There is also a lack of flexibility. You said that you want to allow users to share categories and your schema seems to support that. What I don't see is anything that allows two users to work on different tasks on the same project. That seems to be something that could happen in real life.
I'm puzzled about the User_Category table. Do categories apply to both users and projects?

Complex user relationships in Rails/Devise app

Rails app using Devise for user authentication. Started simple, now getting quite complex.
There are 3 kinds of user that will be logging in to the site: Admin, Teacher, Parent. I have a single Devise User model and User.role string for these. There is a Student model (which doesn't log in) and a Lesson model.
These are the relationships I need:
Lesson belongs to one Student
Student has many Lessons
Student has many Teachers
Student belongs to one Parent
Parent has many Students
Teacher has many Students
Basic functionality of the site: Teachers log in and make lessons for their students. Parents log in and see all lessons for their kids (students). Admins log in and can CRUD teachers, parents and students.
I have most of it working but got stumped when I tried to implement 'student has many teachers' and 'parent has many students'. My initial (incorrect) assumptions were that a student only has one teacher and that a parent just has one child at the school.
So it seems that using a User.role string won't suffice for these relationships.
Any advice or general concepts would be greatly appreciated.
Are you just looking for a join table, ie a has_and_belongs_to_many relation?
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
As I see it:
class Student
belongs_to :parent
has_and_belongs_to_many :teachers
end
class Parent
has_many :students
end
class Teacher
has_and_belongs_to_many :students
end
There can be multiple ways of solving this, what i understand is that you have solved this much but you have made things bit complex.
you can simply have 1 model `User' and remaining things can be polymorphic.
You can move the common attributes in User and separate the remaining in their corresponding models.
It would be much better if had a look at code.
Thanks
I ended up creating a third model and using has_many :through => to link everything together. I wanted to keep a single Devise user model and use a .role for authorization.
The third model I created was Timeslot, which is essentially where a teacher and student interact. Ideally I would have called it class or session but they're both reserved words.
# timeslot.rb
class Timeslot < ActiveRecord::Base
belongs_to :user
belongs_to :student
end
# user.rb
class User < ActiveRecord::Base
ROLES = %w[admin teacher parent]
has_many :timeslots
has_many :students, through: :timeslots
end
# student.rb
class Student < ActiveRecord::Base
has_many :lessons
has_many :timeslots
has_many :users, through: :timeslots
end
This allows a user with a teacher role to have many students and vice-versa. The Student model has a parent_id column which stores the id of the user with role parent. That part is still a bit clunky but it works fine for now. I'm sure I'll have to refactor to something more elegant if the app has to scale.

how to access data with has_many :through relation

Hi I have three models: company, plan and subscription with following association
class Company < ActiveRecord::Base
has_one :plan, :through => :subscriptions
has_many :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :plan
belongs_to :company
end
class Plan < ActiveRecord::Base
has_many :subscriptions
has_many :companies, :through => :subscriptions
end
I have two plans in my application plan 'A' and plan 'B'. Plan 'A' is free and 'B' has some fee. Now i want to get companies registered with plan 'A' and companies with plan 'B'.
I want this data in my model, i know their is definitely a simple way to get all this but
every thing i have used i not giving me right data.any help would be thankful.
To get companies registered with plan 'A' and companies with plan 'B'.
Take object of plan, and then through following relationship code, you will get count of companies.
This is join concept.
eg. #plan is object of Plan 'A'.
then #plan.companies.count.
I suggest to use "polymorphic association" concept.
You need to insert new records through the association. Here is a related link that might help. how to add records to has_many :through association in rails
But a Pseudo-code will be like
1. You have a company object
2. you will have company.subscriptions
3. Insert new Plan objects in company.subscriptions
4. Save the data.
If you are still facing problem, I will try to add some code example.

Access has_many active record associations at deep of two level?

I am currently working on Rails 3 application which deals Account and Users. I am trying to build active record associations on models. For the current implemetation, I have Account, User and Contact Models. But this involves a polymorphic relations, too. I do have one more separate table called as Relation table which stores these has_many relation's id in it.
Account:
has_many :users, :through => :relations, :as => :asset
User:
has_many :contacts, :through => :relations, :as => :asset
Relation:
belongs_to :asset, :owner
For ex: Account1 has 2 Users. And each User has 2 Contacts under them. Below is Relation table:
Asset Owner
User1 Account1
User2 Account1
Contact1 User1
Contact2 User1
Contact3 User2
Contact4 User2
This keep the tracks of every associations. Each model has_many association defined.
The thing which I am facing a problem to build association is::
I need to build association from Account to Contacts so that I can lists all contacts that are under User1 and User2, also under an account.
I can perform operations like Account = User1.contacts + User2.contacts.
But this wont be apt.
So is there any concepts in Rails 3 to achieve like ( account.contacts ), so through this instead of iterating over each User to get contact list and then sum them up, I can have contact lists directly ?
Any kind of suggestions are welcomed...