Rails model structure for users

后端 未结 6 753
长情又很酷
长情又很酷 2021-02-04 19:09

I\'m new to rails, and I\'m working on my second rails app.

The app will have different roles for users, but some users will have multiple roles.

Every user of t

相关标签:
6条回答
  • 2021-02-04 19:28

    I think you don't have to create different models because you don't have specific fields for each one. So you just have to set the "role" of each User. Two options : create a role table or add a role field in the table User. Both solutions work, the second is more flexible but less optimized.

    But, in your particular case, you don't have a complex role management so you can find a simpler solution. If all of your users are artists you don't have to specify this in your code, it's contained in the implicit description of what a user is. So you just have to save if a user is an admin or not and I think the best solution is to create a boolean field "is_admin".

    After that you will have to create some before_filter in your protected controllers, like that :

    before_filter => :authorize, :only => :new, :edit, :create, :update, :destroy
    
    def authorize
      redirect_to :root if not current_user.is_admin?
    end
    

    And you can have simple requests like that :

    @artists = User.all
    @moderators = User.where(:is_admin => true)
    

    If you look for a more complete authorization system you can check this small gem : https://github.com/ryanb/cancan

    But I think it's not the case for the moment. If you have a simple problem look for a simple solution !

    0 讨论(0)
  • 2021-02-04 19:39

    You can have two models User and Role. And Role belongs to User.

    Specify role of users (like admin, moderator) in Role model.

    0 讨论(0)
  • 2021-02-04 19:41

    You can look for gems Devise and CanCan. This pair is really powerful combination. This makes two models User and Role. In Role you can create new roles, without creating new models for them. Although it creates model Ability, here you can define access rules for roles.

    Manual: http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/

    Here you can find Devise's and CanCan's sources and wikies:

    https://github.com/plataformatec/devise

    https://github.com/ryanb/cancan

    My models looks like this:

    Role.rb

    class Role < ActiveRecord::Base
      has_and_belongs_to_many :users
    end
    

    User.rb

    class User < ActiveRecord::Base
      has_many :accounts
      has_and_belongs_to_many :roles
    
      # Include default devise modules. Others available are:
      # :token_authenticatable, :confirmable, :lockable and :timeoutable
      devise :database_authenticatable,
             :recoverable, :rememberable, :trackable, :validatable
    
      # Setup accessible (or protected) attributes for your model
      attr_accessible :email, :username, :password, :password_confirmation, :remember_me, :role_ids
    
      def role?(role)
        return !!self.roles.find_by_name(role.to_s.camelize)
      end
    
    end
    

    Ability.rb

    class Ability
      include CanCan::Ability
    
      def initialize(user)
        user ||= User.new # guest user
    
        if user.role? :administrator
          can :manage, :all
        elsif user.role? :operator
          can :read, Account
          can :read, Server
        elsif user.role? :customer
          can :manage, Account
          can :read, Server
        end
      end
    end
    

    In the controller you must add only this two lines:

    class YourController < ApplicationController
      before_filter :authenticate_user!
      load_and_authorize_resource
    
      ...
    
    end
    
    0 讨论(0)
  • 2021-02-04 19:41

    This is the basic setup, for the declarative authorization gem, I use. But you could just use this as is without the gem, if your authorization requirements aren't more than asking the kind of Roles the User has.

    It does require a roles table, and such, so that might not really be your fancy.

    class Role < ActiveRecord::Base
      belongs_to :user
    end
    
    class User < ActiveRecord::Base
      has_many :roles
    
      def role_symbols
        roles.map { |r| r.title.to_sym }
      end
    
      def admin?
        has_role?(:admin)
      end
      # include more role booleans or write some ruby magic to be DRY
      # ...
    
      def has_role?(r)
        role_symbols.include?(r.to_sym)
      end
    end
    
    # give or take
    user = User.new
    user.roles << Role.new :title => "admin"
    user.roles << Role.new :title => "artist"
    
    user.role_symbols # => [:admin, :artist]
    user.admin? # => true
    user.has_role?(:artist) # => true
    
    0 讨论(0)
  • 2021-02-04 19:43

    If you need to have code that's specific to and role or such as an admin or moderator one other solution would be to create a base User model that all the other classes inherit from. You can then create an Admin class and a Moderator class that inherit from the User model. This would mean you can avoid constantly checking the users role in your code e.g. current_user.do_some_admin_thing if current_user.is_admin?. Your classes would look something like this

    class User < ActiveRecord::Base
      # base user methods in here
    end
    
    class Moderator < User
      def do_moderator_thing
        # perform a moderator task
      end
    end
    
    class Admin < Moderator
      def do_admin_thing
        # perform an admin task
      end
    end
    

    In this instance the User class has the most basic privileges, moderators can do everything users can plus the moderator specific methods and admins can do everything users and moderators can plus the admin specific methods.

    All the different user roles would use the same table in the database but your concerns are neatly separated into classes which avoids excessive conditionals through your code checking what role the user is all the time.

    Creating new users would be straightforward also Admin.new :name => 'bob' the Admin class then takes care of how a user is defined as an admin which provides a nice interface where you don't need to know the inner workings of the role system to interact with users.

    0 讨论(0)
  • 2021-02-04 19:45

    Although I agree the combination of Devise and CanCan is powerful and works. Let us look at it with a different perspective keeping Association and Delegation in mind.

    Association: In object-oriented programming, association defines a relationship between classes of objects that allows one object instance to cause another to perform an action on its behalf.

    Delegation: Delegation allows the behaviour of an object to be defined in terms of the behaviour of another object. The term 'delegation' refers to the delegation of responsibility. The primary emphasis of delegation is on message passing where an object could delegate responsibility of a message it couldn't handle to objects that potentially could (its delegates).

    With that, what if we design our User and Roles like this. There is no Role class and the User doesn't inherit or specialise a particular class ( Artist, Admin ) instead, all the (Role) class contain the User object and delegate. The way I am thinking and way to implement with Rails is something like this:

    class User < AR::Base
      def user_method
      end
    end 
    
    class Artist < AR::Base
      has_one :user
    
      def artist_method
        # perform an admin task
      end
    end
    
    class Admin < AR::Base
      has_one :user
    
      def admin_method
        # perform an admin task
      end
    end
    

    This role class model is described by Francis G. Mossé in his article on Modelling Roles.

    0 讨论(0)
提交回复
热议问题