set attributes in a has_many_though relationship in Rails - ruby-on-rails

I have three models: Company, User and Employment. Each Company has many users though their Employments, and a user might belong to several companies through his employments.
Now, the tricky part: let's say my User1 belongs to 2 companies. He is SUPER_ADMIN in the first compnay, but just BASIC_USER in the second one. What would be the best way to define his roles ?
I used to have a simple has_many relationship between Company and User, which allowed me to simply set a is_admin attr on my User, but obviously this won't do with the new HMT relationship.
I thought of defining an array of IDs for each company, that would include the IDs of each admin user, but I'm pretty sure there is a cleaner way around.

In above scenario, you can use intermediate table i.e. Employment table to save all details of a user and it's associate company.
As Employment table will have ids of both user & company it will be easy for you to keep extra information related to user and company. Just add role column in this and use this to get information

Related

Rails associations: hash of ids within one column needed?

I have a User model and a Company model, and I want each user to have a variable number of companies (that they have worked at), that can be pulled by e.g. current_user.companies.
The list of companies is provided by me, not the users, and is fixed.
I don't think I want
to have separate columns in the user model for e.g.
Company 1, Company 2, Company 3, as some users may have worked for 10
companies, some only 1...
to put user ids in the company model, as there are
multiple users...
How would this work in Rails associations? Do I need to have multiple company IDs in a hash in one column of the User Model to achieve this? If so how do I do this, or is there another way?

Rails - a model that can have two different sub items

I have a standard devise user model with the usual fields.
This is for a situation where people are either looking for a place to stay, or they have a place to stay. So I have two categories of user that a person can be. These two categories are very distinct (i.e. a person looking for a place to stay will have very different fields to a person who has a place to stay).
So a User has:
User: name, email, password, profile_id
A User can also have a Profile (i.e. they are looking for a house).
Profile: age, sexuality, religion, occupation
That's what I have at the moment. Now I need to change that slightly, so a User can have a profile OR... they can have a House (i.e. they have a house and are looking for more people):
House: price_per_week, address, etc
How best to model this in ActiveRecord? Polymorphic association of some kind?
I've found in general that polymorphic relationships don't work well over time if the objects they are modeling are even mildly different. For your case I'd recommend keeping the two objects separate.
In general, the best way is to consider the way you want to retrieve the data. For example, I'd imagine you want to access both:
#user.house
or
#user.profile
So I'd recommend beginning by setting up relationships (that can be optional) between the users table and both the profiles and houses table. I'd also add a type field that can be used to determine which of the two types the users are.
This allows users to be of either type and allows them to have both a profile and a house.
So both houses and profiles belong_to users, and users have_many (or have_one) houses and profiles

Modelling Company and Person Customers in Rails

My Rails application uses STI where I have different types of companies and persons. For example I have suppliers, manufacturers and customers as types of Company. I have also employees, contacts and customers as types of People.
Now I want to refer to a Customer which can either be a Company Customer or a Person Customer. Which method can I use/should I use to combine these two different entities into one? So I can refer to a Customer, from an Order?
You could either use:
Order
belongs_to :company
belongs_to :person
end
And have two foreign keys - and then add some validations to make sure one of them is filled in, and then maybe add a 'customer' method which returns either the related company or person, depending which is used.
OR, create a separate Customer model (and table), which has those two same two foreign keys, and then Order can simply belong_to :customer. This second method may be preferably if you want to store additional data at the customer level (such as credit limit, or billing details), and may be cleaner long-term.
Alternative, you could reconsider your business logic, and insist that all orders belongs to a Person, even if that person is an employee of a Company and is purchasing on behalf of the company.
F

Authenticating multiple models with Authlogic

I have multiple user account types, each with different information. For example, business contacts link to businesses, school administrators and students link to schools. Students have physical addresses, but business contacts and school admins use the organizations address. There's other information unique to each type as well.
I'm leaning toward separate tables for students, school admins and business contacts, but using Authlogic, I have a Users table with authentication information (all need to log in).
The question is really how best to link this single authentication table with the individual profiles. It seems like a one-to-one relationship requires a single table (e.g. Users <-> Students or Users <-> Business_contacts). I want to have something of a "one-to-one-of-the-following" relationship (Users <-> Students or Business_contacts). Is there a good way to do this using a join table or other construct?
Alternatively, I could unify the common information in the Users table and come up with a "profile" column in XML to support the unique information. My thought was that keeping everything in clean DB columns would simplify selects/inserts.
Thoughts, ideas?
business contacts link to businesses, school administrators and students link to schools.
This means you have different roles of users rather than different users.
Students have physical addresses, but business contacts and school admins use the organizations address
There's other information unique to each type as well.
Which means different roles have different data and behavior, leading to different OO classes.
The question is really how best to link this single authentication table with the individual profiles.
I want to have something of a "one-to-one-of-the-following" relationship (Users <-> Students or Business_contacts). Is there a good way to do this using a join table or other construct?
The simplest model I can think of if the following:
User (Username, Email, Password, Names and other common data for every user)
Participant, abstract. (has relation to one user - defines the role of the participant, behavior and its common data). Should provide the interface for participants.
Student (inherits from Participant, adds its own behavior and data)
SchoolAdministrator (inherits from participant)
And so on
In the Object Oriented World (non RDBMS) this has a simple advantage: polymorphism. Having a user you don't need to know exactly who he is. You just do things like this:
user.participant.can_manage_stuff?
user.participant.order_book(harry_potter)
And the appropriate actions will take place which will be implemented in Student, SchoolAdministrator or other class inherited from Participant.
Another things is that it is very easy to add new roles for the system. Just inherit from Participant and implement its interface.
Now, when Object Oriented Design is done, let's have a look at the data storage. I assume you use RDBMS.
So now you have 2 types of links:
One-to-one association between User and Participant.
Generalization (inheritance) between Participant and Student, SchoolAdministrator.
Implementation of 1st is as simple as having has_one and/or belongs_to association for the following table (via participant_id column):
users:
id | username | email | password | etc | participant_id (non-null) FK_TO_participants table |
So you can easily implement that.
Now, the 2nd link can be implemented in RDBMS in number of different wasy.
But fortunately or unfortunately ActiveRecord supports only one option to do that. And it is hierarchy per table mapping strategy that uses discriminator column to distinguish the type (stored in type column by convention).
So you will have the 2nd table that looks like this:
perticipants:
id | type | student_card_number (null) | administrator_number (null) | etc
This table will have all the columns for all possible participants. This is the simplest and easiest implementation of hierarchy in DB. But not the most optimal from some points of view. As I said with ActiveRecords it is only one option available anyway.
So as a result of this design you will end up with 2 database tables (users, participants) and at least 3 classes (User, Participant, Student).
And, of course, you can vary from here a lot but that should deliver my point.
And yes, please no XML in database, don't waste your nerves and valuable personal time.
Cheers.
If you really need seperate models for each role you use, then I would recomend to use polymorphic association (read more here). So:
# User model
belongs_to :owner, :polymorphic => true
# Student model
has_one :user, :as => :owner
# Any other model
has_one :user, :as => :owner
And you need to add to users table:
t.integer :owner_id
t.string :owner_type

validates_uniqueness_of scope on other table

A User belongs to Groups, a Group belongs to a Company
I want to verify that the username of the user is unique per company. So my database can have multiple dublicate usernames as long as they belong to a different company.
A logical step would be to use validates_uniqueness _of scope and use the company id (stored in groups). Is there a way scope can get access to other tables or do I need to solve this ina different way?
thanks
In this design, I see a problem, if a User can belong to one group, and that a group can belong to one company. But the association of User and Company is very indirect, where as in reality it should be direct, independent of its association with the group.
So for example to change companies a User switches groups, not companies, which is not entirely right. It may make sense in your context I am not sure.
So storing company information in the User table would make sense ( as for uniqueness test as well, the relationship is direct).
and
validation_uniqueness_of :user, :scope=> company_id
would work.
Update
I am not asking you to denormalize tables, the group still may be tightly tied to the company. But that relationship has nothing to do with the user-company
My point is basically, User object should have direct visibility into the Company class, not through "Group".
That means adding a company column into your table, thats all, and establishing a direct relationship b/w user and Company.
and it wouldn't be so much of a management hassle.Plus, I sort of expect, to write something like
"user.company"
Instead of
"user.group.company".
In any case. Thats just my view, I don't know the whole context, so my advice is based on what I saw in your question
Making a custom validation rules is probably the best way to tackle this problem.
I had this issue as well and came to research an answer. I used Tarscher answer to come up with the following solution.
validates_each :username do |record, attr, value|
if User.joins(:group).where('username = ? and groups.company_id = ?', record.username, record.group.company_id).present?
record.errors.add attr, 'This username is already taken by some on in your company'
end
end

Resources