In the project i'm currently developing under rails 4.0.0beta1, i had the need for a user based authentication in which each user could be linked to an entity. I'm kinda new to rails and had some troubles doing so.
The model is as following:
class User < ActiveRecord::Base
end
class Agency < ActiveRecord::Base
end
class Client < ActiveRecord::Base
belongs_to :agency
end
What i need is for a user to be able to link to either an agency or a client but not both (those two are what i'll be calling entities). It can have no link at all and at most one link.
First thing i looked for was how to do Mutli-Table inheritance (MTI) in rails. But some things blocked me:
- it was not available out of the box
- MTI looked kinda hard to implement for a newbie such as me
- the gems implementing the solutions seemed old and either too complexe or not complete
- the gems would have probably broke under rails4 as they had not been updated for a while
So i looked for another solution and i found polymorphic associations.
I've be on this since yesterday and took some time to make it work even with the help of Rails polymorphic has_many :through and ActiveRecord, has_many :through, and Polymorphic Associations
I managed to make the examples from the question above work but it took a while and i finally have two problems:
- How to transform the relations in user into a has_one association and be able to access "blindly" the linked entity ?
- How to set a constraint so that no user can have more than one entity ?
- Is there a better way to do what i want ?
Best Answer
Here's a fully working example:
The migration file:
The models:
As you can see i added a getter and a setter that i named "entity". That's because
has_one :entity, through: :user_entity
raises the following error:Finally, here are the tests i set up. I give them so that everyone understands know ho you can set and access data between those objects. i won't be detailing my FactoryGirl models but they're pretty obvious
I Hope this can be of some help to someone. I decided to put the whole solution here cause it seems to me like a good one compared to MTI and i think it shouldn't take someone that much time to set something like that up.