Sanity check my Rails "Roles and Users" approach with Devise and Cancan - ruby-on-rails

been kicking this one about for a while now, and would like to get someone who knows rails to test my theory (I'm new to Rails).
In my (simplified) scenario, I want to manage a list of Users, some of which are, for example, "paid" users, some are "free" users etc, and there is a straight "isa" relationship. i.e. a paid user isa user, a free user isa user etc
To reduce redundancy and to keep it semantically correct, I want to manage all the users in one table and use a foreign-key back to the correct "type" of user, so I can create a role of the correct type. e.g. I would instantiate a User, get the id and store this in the user of correct type e.g. "PaidUser" in the "user_id" foreign-key. This gives me the ability to store specific metadata I want to store against them, and I don't have to have one table ("users") with every field for every type of user.
This sort of feels like a confusion of roles and types of users. My question is, is using the approach above going to make life difficult? Is there an accepted approach to this in Rails that I'm missing? I'm using Devise and have removed all routes except for /users/ thinking I would pass a "type" as an argument, and use that type to create the corresponding "real" type of record at the same time as the user. Is this bad practice too?
Thanks in advance

What you're doing sounds fine, but to be honest unless you have a lot of these different properties between user types I would just put them all in the same table. It's not really a big deal to have a couple of blank columns here and there, especially when it saves you from having to do a whole load of difficult stuff. If this starts to seem unwieldy then you can worry about what to do then - it would still be easy to change. You could even then potentially use Single Table Inheritance to give all the different user types their own class that inherits from the base User class, which is where you take care of all the authentication etc.
If you immediately go with something more complex then it will be much harder to unravel if it turns out to be wrong than if you start with something simple. If you go with the multi-table approach then make sure you name them sensibly. I would go with PaidUserProfile etc.

Related

Ruby on Rails: Should a single field ever get its own model?

I'm new to Ruby on Rails. I have a relatively simple question. I'm modeling users. I want users to be able to have a short "profile message" that they can edit and that gets displayed on their profiles. Would it make sense to make ProfileMessage its own model? Or, should profile_message be one column in a table that contains user settings?
I feel like an entire model just for one string is a little bit overkill and if I start going that route, I'm going to end up with so many models that things become cumbersome.
What does the community think?
I would keep your data structure as simple as possible when starting out. For a profile message, it doesn't make much sense to have it be it's own model. Only if profile_message were to later on have it's own set of attributes and behaviors, or if users could have more than one profile message...then I would consider moving it to a separate model.
Table joins in SQL consumes a lot of resources when you are not using them properly. In your case i think that making a new model only for the one profile_message is not a good practice.However, it should be implemented inside the user/profile model.
This approach is going to make accessing the message faster, on the other hand if you are using a whole table for the profile_message will make the response time slower because you will need to look for it every time in the profileMessages table which will take more time depending on the number of entries in that table.

How to set up Rails app that has different types of users?

If I want to build a Rails app that has two different types of users, let's say one type is called players and the other one is owners, what is the best and most efficient approach to modeling the app?
Things to take into account:
There should only be one Login, but different Registration forms that Owners/Players can use.
Owners can have access to a control panel but Players cannot.
Owners cannot share any of Players capabilities, but both need to be able to perform Login/Registration.
I am not using Devise, so please do not suggest it.
Different Approaches I've considered:
Using cancancan gem, but it does not really seem to meet my needs in the sense that I am not looking to create a user/admin hierarchical approach but rather a if you're a Player, then you can see these pages and perform these actions but Owners cannot and vice versa. Almost like splitting the app in two. cancancan seems that it would treat Owners as "Players with extra privileges", not different privileges entirely.
Creating separate models with separate login and registration forms, which seems like a disaster waiting to happen. One small mixup between a Players table and the Owners table, especially with the primary keys, and that will be a world of trouble where people could end up logging in to the wrong accounts.
Creating a polymorphic or has_one relation toward an Account model, which so far, seems like the best way to probably go about it. If I created a polymorphic Account model, I can store different types of Players/Owners, but how could I compare login credentials against all types?
I had been trying to find something on this matter regarding how to map this out and was surprised to not find an information on how to do this without using Devise. If anyone has any good links they can point me to that also address this matter (without Devise), please leave them in your answer! Thanks.
I'd suggest one User class with a type attribute that determines whether the user is a Player or an Owner (single table inheritance). This way you keep the registration logic in one place but can customize the forms depending on the user's class.
There must be alternatives to cancancan that help with what you want to do, or you can implement helpers yourself:
def can_access_control_panel?
current_user.is_a?(Owner)
end
You have to have a way to separate one user from another. One way is to add an attribute to the User table so you can call current_user.role and it will return "owner" or return "player".
I have used Pundit gem in the past. It lets you define which controller actions the current user is allowed to access. So as you create resources for your application, you can add a policy that specifies who is allowed to that given resource. This is the repo to the application.
This answer might help you.

not sure whether to create new models

I'm making an app with Rails that, among other things, allows certain types of professionals to create an online profile. So there is an 'association' between the User and Profile model. I created the Profile model so that I can basically restrict the User model to name and registration information, and keep profile information elsewhere (i.e. 'normalize' the db as I think it's called)
However, these profiles (as is often the case, on LinkedIn, for example) contain a lot of information. For example, there will be a section for Work Experience that sometimes looks like this, where a user can add many different work experiences.
and then something similar for education
And many other different types profile information. Note also, that the ability to add to and edit these discrete categories takes place in separate forms. I can add to my work experience without touching education.
My question is, should I try to store all of this information in my Profile model? Or, would you, for example, create a WorkExperience model and do something like Profile :has_many work_experiences? and something similar with EducationExperience, or is there even another way to do it?
One of my concerns is queries on the DB. For example, in terms of performance, is there going to be much of a difference if, in the show action of the Profile controller, I do queries for WorkExperience.all, Education.all rather than storing all the information in the Profile model?. Another concern is just general code organization for profiles that can become quite large.
You'll have the cleanest code (and decent performance) by splitting out something like Experience (which will belong_to Profile), along with a type column that determines whether it's "work" experience, "education" experience, etc. That's the approach I would take, unless the different types of experience have vastly different columns.

RoR table inheritance?

Scenario: I have a users table in my application. I also have two subclasses of users, lets say contributors and viewers. Each user group must have an entirely different set of attributes but they both share certain user properties (login, password, name).
What is the best way to implement this using Ruby on Rails?
I think single table inheritance would leave me with too many null fields.
I think linking three tables (users, viewers, contributors) would work fine, but then when wanting to edit any information i have to do: #user.viewer, while i would love to be able to just do #viewer.
Any ideas of the best solution?
I would probably go with the three tables approach. Data integrity is king over code cleanliness.
If you want to make it look neater, put virtual attributes on the Viewer and Contributor models that make it look like the User attributes are local. You can make it a module and include it in both Viewer and Contributor models.
You can also set up an :include => :user on the default finders so that you don't get an extra query when using those fields.
I'm extremely caffeinated right now, so comment back if that doesn't make sense :)
don't compromise the database schema, make it fit best. I like the three table method. If you do the database bad, the application will have very hard to fix issues later, run slow, etc.

How to label :id in Ruby on Rails apps?

I am building my first rails application and I expect it to eventually have many models/controllers. And of course they each have an ID associated with them. I can see that they are starting to get confusion already.
In the users controller the field is called id, but in every other controller i label it as user_id. When a controller is manipulating multiple models or calling actions in other controllers, it seems tedious to keep all the ids straight.
I would like to just prefix them all to be explicit, but am afraid this might cause errors down the road as user does not actually have a user_id field. This would be an issue when using something like update_attributes!.
Has anyone else experience this problem? Is it really a problem or am I making this into a bigger issue than it actually is? Are there any standard best practices for naming the id field?
Thanks!
Dave
This is really not a problem. The convention in Rails is to label the primary key of the table as id, and any foreign keys that access that table as table_name_id.
I'd advise against changing this default behaviour as Rails is more about convention over configuration, and this method of naming does actually make your DB schema far easier to understand as complexity grows.
If you do decide to change the primary key name, there is also the chance that you will run into further problems when using other peoples gems and plugins.
As far as I know the best name for id field is id.
I have application with about 30 models and almost the same number of controllers. I manipulate many models in single controller and I didn't ever have any problem with id. Maybe we could help you a little more if you paste some code.

Resources