Несколько типов пользователей в Ruby on Rails

Я новичок в Ruby on Rails и слежу за учебником. Но мне нужна дополнительная информация.

Я создаю приложение, которое позволит доступ к различным типам пользователей, это студенты, родители, учителя и администрация (все они имеют одинаковые атрибуты) Пока у меня есть модель для пользователя, в которой есть поля, электронная почта и пароль, которые служат в качестве учетных данных для входа на сайт.

Затем у меня есть шаблон для каждого типа пользователя. Модель Студент Модельный учитель ....

Что я хотел знать, так это то, как зарегистрировать пользователя, обращаясь к каждому типу пользователя, и у меня уже есть таблица User.

Я искал, и я понял, что использование "devise" будет жизнеспособным решением, но не совсем понимает, как это работает.

Кто-нибудь объяснит мне лучший способ сделать это?

Ответ 1

Существует несколько способов решения этой проблемы, как указывают другие ответы. Во-первых, убедитесь, что вы понимаете разницу между аутентификацией (создание пользователя и вход в систему) и авторизация на основе ролей (контроль доступа к различным частям веб-приложения в зависимости от роли пользователя). Вы можете реализовать аутентификацию самостоятельно, но большинство разработчиков Rails используют камень Devise, потому что он надежный, полнофункциональный и хорошо протестированный. Авторизация может быть реализована с помощью простых дополнений к модели пользователя, хотя разработчики часто используют CanCanCan или Pundit для сложных приложений.

В описываемом вами случае использования я рекомендую внедрить в вашей модели пользователя очень базовую форму авторизации на основе ролей. Сначала вам нужно создать модель User с помощью Devise.

Новая функция Active Record, Enum, введенная в Rails 4.1, является самым простым способом реализации авторизации на основе ролей.

Создать перенос:

$ rails generate migration AddRoleToUsers role:integer

Миграция будет выглядеть так:

class AddRoleToUsers < ActiveRecord::Migration
  def change
    add_column :users, :role, :integer
  end
end

Добавить код в пользовательскую модель для реализации Enum:

class User < ActiveRecord::Base
  enum role: [:student, :parent, :teacher, :admin]
  after_initialize :set_default_role, :if => :new_record?

  def set_default_role
    self.role ||= :student
  end

end

Вы определяете имена ролей и, при необходимости, можете изменять имена по мере необходимости (целочисленные значения, сохраненные с каждой пользовательской записью, остаются неизменными). Активная запись ограничивает присвоение атрибута коллекции предопределенных значений, поэтому вам не нужно добавлять какой-либо код, чтобы ограничить имена ролей определенным набором. Лучше всего, перечисления поставляются с набором удобных методов, которые позволяют вам напрямую запрашивать роль без какого-либо дополнительного кода. Для атрибута enum, показанного выше, вы можете использовать следующие методы:

User.roles # => {"student"=>0, "parent"=>1, "teacher"=>2, "admin"=>1} # list all roles
user.student! # make a student user
user.student? # => true # query if the user is a student
user.role # => "student" # find out the user’s role
@users = User.student # obtain an array of all users who are students
user.role = 'foo' # ArgumentError: 'foo' is not a valid, we can’t set invalid roles

Вы можете использовать условные обозначения в контроллере:

class UsersController < ApplicationController
  def index
    unless current_user.admin?
      redirect_to :back, :alert => "Access denied."
    end
    @users = User.all
  end
end

Или используйте его в представлении:

<% if current_user.parent? %>
  <li><%= link_to 'Grade Reports', some_path %></li>
<% end %>

В общем случае, если управление доступом добавляет много кода контроллеру, вам рекомендуется использовать CanCanCan или Pundit, поскольку вы можете переместить сложную логику авторизации в центральное место, отделенное от контроллеров ( "тощие контроллеры" ). Однако, если ваши потребности так же просты, как вы описываете, роль авторизации на основе роли в контроллере является оптимальной.

Я написал учебное пособие > Rails Pundit, в котором сравниваются оба подхода и более подробно описывается простая авторизация на основе ролей, а также роль авторизация с Pundit.

Ответ 2

Ну, вот как я его реализую.

1) создайте модель учетных записей и добавьте полиморфную ссылку в ее переносе, например

  class Account < ActiveRecord:Migration
    def change
      create_table :accounts do |t|
        t.references :user, :polymorphic => true
        t.column :name, :string
      end
    end
  end

2) В каждом классе модели, например, классе ученика я бы добавил следующую строку кода

  class Student < ActiveRecord::Base
    has_one :account, :as => :user
  end

3) В классе модели учетных записей

  class Account < ActiveRecord::Base
    belongs_to :user, :polymorphic => true
  end

4) Используйте генератор генератора для модели Account.

5). Большой проблемой является создание нового ученика, в основном вы создадите запись учетной записи, а затем назначьте эту запись учетной записи вновь созданной записи Студента.

a) Есть два способа сделать это:     * Использование вложенных форм.     * Использование простой формы и заставить контроллер выполнять работу.

Я бы посоветовал второй вариант, выберите то, что подходит вам лучше всего, и дайте мне знать, если у вас возникнут проблемы.

Ответ 3

Если вам нужны разные разрешения приложений, возможно, вы хотите назначить роли своим пользователям. Это можно осуществить разными способами. Легко использовать Rolite gem: https://github.com/EppO/rolify

Ответ 4

В самой простой форме вы хотите иметь возможность выбирать тип пользователя при его регистрации.

class User
  belongs_to: user_type
end

class UserType
  has_many: users
end

Исходя из этого простого отношения "один ко многим", вы можете передать в user_type форму в контроллер и позволить контроллеру заботиться о создании/ассоциировании объектов

user = User.create(params[:user])
user.user_type = UserType.find(params[:user][:user_type])

Что-то очень простое и быстрое сочетание кода с намерением сделать мою точку немного яснее.