Rails polymorphic association - controllers and views? - ruby-on-rails

I have a model User (used for authentication purposes) which is connected to two other models, Customer and Seller via polymorphic association in Rails. A customer and seller must have different sign up forms because of their different data but can use a single login form because they're both Users. In order to manage the customer and seller resources separately, is it a good idea to create respective controllers and views for them, or should management of all Users be done in the UsersController?

It depends upon the design of the two views customers and sellers. If the design of both the views are different then I will encourage you to create two controllers customers_controller and sellers_controller and you may want to have a module for common actions like lib/authentication.rb.So
# customers_controller.rb
include Authentication
def some_action
end
and
# sellers_controller.rb
include Authentication
def other_action
end
Authentication file like
# lib/authentication.rb
module Authentication
def common_method
end
end
You can have two controllers and one module which you can write common methods/actions

As #madyrockss pointed out, STI is probably the way to go here because User.find(params[:login]) will return either an instance of Customer or Seller automatically.
I would encourage forgetting about the UsersController and views and encourage thinking in terms of seller and customer controllers/views (that is, don't share a single controller and views per action that can handle either customer or seller and has conditionals within view determining what to show). If the two users have different business rules, the whole thing starts to get messy real quick and becomes unwieldy to manage as business rules change.
For login/logout, if the form is going to be the same for both, then a single controller will suffice and I'd consider a different name than UsersController, such as SessionsController to be more semantically in line with what the controller's purpose is. You are not confined to a one-to-one Models <==> Controllers <==> Views which many beginning Rails developers fall into the trap of.

Related

Devise Model inherit from another devise model

I'm creating an online real estate platform which facilitates (normal) Users and Real Estate agencies. This platform has following user types:
Normal Users: can search houses for rent/purchase, reviews agencies
etc.
Agencies: can upload posts for house rent/sell etc
Employee: works for a Agencies
Super Admin: manages the site
Team Member: manages portions of the site delegated by Super Admin
Each user type then has different fields (4 - 6 additional fields each). Normal Users and Agencies can self-register. Employees and Admins can be registered by Agencies and Super Admins respectively. Furthermore there are some different multiple roles for a user type (which is not relevant to discuss for this case).
Currently, I have three different devise models (User, Agencies & Super Admin). They have different login and registration forms but share same session [Reference: [https://github.com/plataformatec/devise/wiki/How-to-Setup-Multiple-Devise-User-Models]][1] User has facility to register via social media (OmniAuth) but Agency must has to register via private Email Id. And Admins will only be registered by Super Admins.
Here comes requirement [PROBLEM]:
The following fields are what I've identified as being shared between the three user types above: Email address & Username They must be unique for all cases. For example, if an agency has a username then user can't register with same username. At the moment, we are not meeting above requirement as we have different tables/models for different type of user.
MY PLAN
Now, since these are all really different users who interact with different sections of the application, so it feels clean to have three different devise models. Therefore, what I think is to create a parent devise model which should be inherited by all type of user models. This way can help me to solve my problem. But now, I'm not confident that how can I inherit parent devise model and use it for my case.
Second option is to use STI (Single Table Inheritance). But my major concern with this approach is that it will create mess with registration and security things.
Now here is my problem with my researched options. What would you recommend me to chose. Moreover, it'd be great if you put an example for elaboration.
P.s. I am inclined to the first one option as I have already done with three different models and their login/registration stuff. :)
Not sure how your going to accomplish this without a roles system.. I suppose you could namespace or scope it out but wouldnt be the most secure to keep access to a specific user group.. atleast in my oppinion.
You could Use Single Table Inheritance (STI)..
Essentially you could do something like this (if i understand you correctly)
class User < ApplicationRecord
# MASTER
end
class AnotherUser < User
# Inherits attributes from User Table
end
going this route you will need to add type:string to your User model.
here are a few reference links:
http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html
http://eewang.github.io/blog/2013/03/12/how-and-when-to-use-single-table-inheritance-in-rails/
they helped me when i ventured down the STI path..
For example, In a project I did this like so:
class User < ApplicationRecord
# Devise Modules Here
end
class Admin < User
end
class SuperAdmin < User
end
now the tricky part I found was creating these users.. i opted to create a controller and a link, so in my app a User is created only by an admin or superadmin, and an admin can only be created by a superadmin

Multiple Devise Users: Multiple Models or Inheritance?

In my Rails application with Devise, I plan to make multiple types of Users (Student, Teacher, and Admin). They have a number of shared attributes such as username, email, password, etc, but with some differences. Students will be able to interact with the content posted by teachers (and probably each other), Teachers can make classes and post content and interact with their students, and Admin will likely have control over most everything (including taking down users, content, etc.)
I am trying to figure out the best way to do this, and preferably with the least headaches as I am still new to Rails. Should I make multiple Devise Models, one for each type of User, or should I make multiple models inherit from User (which I believe is called Single table inheritance?) I am fairly open to trying either one, but I am unsure of which is the best way to go
If you want different authorizations (for example Admin & User) level you can use Pundit.
If you have different roles with the same authorizations (like Student and Teacher in the same context) you should use Inheritance and Concerns, maybe defining a base controller from which all other controllers can derive.

Rails best practice for backend admin system setup?

We have a site where we have a backend management interface, and a frontend that displays our information. We are using Devise to secure authentication.
The backend should allow for normal CRUD type editing of our model objects. The views and layout are also completely different than the frontend. What is the best practice for implementing this in Rails 3?
Our two approaches are:
An admin view folder houses all view specific code, as well as an admin folder in the controllers folder houses all controllers that control admin specific access.
A conditional logic system with one set of views and controllers, with if statements checking whether the user is in admin mode or not.
Which is more recommended, or if there is another approach we have missed, please let me know.
The first solution is better, however for these cases was created the namespaces and the best practice is to go with namespaces when you need relevant differentiation between user site and administration area. Read more about it here
Your directory structure should look like this:
controllers/
|--admin/
|--posts_controller.rb
In your routes you put everything you need into admin namespace:
namespace :admin do
resources :posts, :comments
end
Your controllers should have an admin folder, and a controller in the admin area will look like:
class Admin::PostsController < ApplicationController
end
You also should have an admin folder in your views, where you put the respective views:
views/
|--admin/
|--posts/
|--index.html.erb
|--...
You can also namespace your models, but it depends on your needs, it is good when you need to have different models with the same name. For example if you need different table for the admin users, and different table for normal users. Personally I wouldn't use model namespacing, just in very justified cases.
The second option I think can cause a lot of headache, you gonna be lost in the if statements, I don't recommend that at all.

Does Devise supports deferent models for deferent roles? (in rails)

I use Devise in my new project,but I have some problems in roles.
There are two kinds of user in my project,but these two kinds of user have deferent data structure(very different).
I Know Devise supports roles,but how should I deal with the deferent user data structure?
Thank you.
Devise documentation states that you can have as many Roles with different models as you want (configuring multiple models)
You just set up the other model as you did with the first one and then add to routes.rb
devise_for :admins
And then you can use inside your controllers and views:
# Inside your protected controller
before_filter :authenticate_admin!
# Inside your controllers and views
admin_signed_in?
current_admin
admin_session
The main question is how to let both of these accounts access the same controller (if it is applicable to your case), because of the two before_filters the first would always redirect to login page, if that is not the logged-in role (say :admin). You would probably have to implement a custom before_filter to validate the session against two roles simultaneously.
You could probably work around this with custom routes for these roles. E.g /admin/projects and /user/projects. In that case the authenticate method could be helpful.

Dedicated controller? How to structure admin feature?

Is it better to extend my users controller to include administrative task on other nested controllers?
Or create a 'profile' controller where I could create different actions and views that summarize admin actions.
Scenario A:
"/users/current/" : would show a link to edit products user own.
"/users/current/products" - Products controller would detect if it is accessed as a nested ressources. If so, would show all user products and edit links to product. In that case, the view would have to be completely different if it is access as nested ressource or not.
Scenario B:
"/profile/" : would show a link to edit products user own.
"profile/products" : products would be an action in profile controller that show all products own by the user with links to edit those products on products controller.
I do find it helpful to separate admin actions from a end-user actions, so I would lean towards the "/profile/" scenario.
But really, it's a matter of personal taste. Just decide which structure you'll most easily recognize in 6 months, when you've forgotten where everything is. Also take into consideration which structure will become less cluttered if you should ever start adding more features (actions) to those controllers.

Resources