devise i wiele modeli "użytkownika"

Używam rails 3.2 i devise 2.0 i jestem całkiem nowy w Rails.

Wymagania

Chciałbym osiągnąć:

  • mieć 2 lub więcej modeli "użytkownika", np. Member, Customer, Admin
  • wszystkie modele posiadają wymagane pola (np. e-mail i hasło)
  • każdy model może mieć jakieś unikalne pola (np. firma tylko dla Klienta)
  • niektóre pola mogą być współdzielone, ale nie mają takiej samej walidacji (np. imię jest wymagane dla klienta, ale opcjonalne dla Member)
  • wszystkie pola muszą być wypełnione podczas procesu rejestracji, więc formularze są różne
  • formularz logowania powinien być unikalny

Możliwe rozwiązania

Przez długi czas googlowałem i szukałem StackOverflow, ale nic nie wydaje mi się właściwe (jestem Javą, przepraszam :) i teraz jestem trochę zdezorientowany. Pojawiły się dwa rozwiązania:

Pojedynczy użytkownik devise

To najczęstsza odpowiedź. Wystarczy utworzyć domyślnego użytkownika devise i utworzyć relacje pomiędzy Użytkownikiem -- > Użytkownikiem a Klientem-- > Użytkownikiem. Moim problemem jest to, w jaki sposób mogę osiągnąć spersonalizowany proces rejestracji dla każdego modelu? Próbowałem różnych rzeczy, ale wszystko skończyło się jak bałagan!

Wielu użytkowników devise

To rozwiązuje niestandardowy proces rejestracji i wydaje mi się słuszny, ale unikalny formularz logowania jest blokerem. Znalazłem odpowiedź na SO (Devise-login z dwóch modeli ) co sugeruje obejście Devise:: Modele:: Authenticatable.find_for_authentication (warunki). To wydaje się skomplikowane (?) a ponieważ jestem nowy w rails, chciałbym wiedzieć, czy to może zadziałać?

Dzięki za radę!

Author: Community, 2012-02-28

4 answers

Witaj na pokładzie Java guy =), mam nadzieję, że spodoba ci się świat Rails. Po prostu, aby rozwiązać swój problem, masz 2 rozwiązania:

  1. dla każdego użytkownika Utwórz tabelę w bazie danych i odpowiedni model.
  2. Utwórz pojedynczą tabelę w bazie danych i dla każdego typu użytkownika Utwórz model. Jest to tzw. dziedziczenie pojedynczej tabeli (STI).

Który wybrać? To zależy od wspólnych atrybutów ról. Jeśli są prawie powszechne (na przykład wszystkie mają Imię, e-mail, mobile,..) i kilka atrybutów jest różnych, Gorąco polecam rozwiązanie STI.

Jak zrobić STI? 1. Po prostu utwórz model użytkownika i tabelę devise używając polecenia rails generate devise User 2. Dodaj kolumnę o nazwie type z string datatype do tabeli user w bazie danych przy użyciu migracji. 3. Dla każdego typu użytkownika Utwórz model (na przykład rails g model admin) 4. Sprawia, że Klasa Admin dziedziczy z modelu użytkownika

class Admin < User
end

To już koniec=)... Yupeee

Aby utworzyć admina Uruchom polecenie Admin.create(...) gdzie kropki są atrybutami administratora, na przykład e-mail, nazwa, ...

Myślę, że to pytanie może również pomóc

 66
Author: mohamagdy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:15

Jestem w podobnej sytuacji jak ty, po wypróbowaniu różnych podejść wybrałem model pojedynczego użytkownika, który należałby do ról polimorficznych. Wydaje się to najprostszym sposobem osiągnięcia jednokrotnego logowania.

Model użytkownika będzie zawierał informacje specyficzne tylko dla logowania.

Model do Naśladowania przechowywałby pola specyficzne dla każdej roli, a także inne skojarzenia specyficzne dla tej roli.

Nowe rejestracje będą dostosowywane dla każdego typu użytkownika (ról) poprzez poszczególnych kontrolerów, a następnie budowanie zagnieżdżonych atrybutów dla użytkownika.

class User < ActiveRecord::Base
    #... devise code ...
    belongs_to :role, :polymorphic => true
end

class Member < ActiveRecord::Base
    attr_accessible :name, :tel, :city  #etc etc....
    attr_accessible :user_attributes #this is needed for nested attributes assignment

    #model specific associations like  
    has_many :resumes

    has_one :user, :as => :role, dependent: :destroy
    accepts_nested_attributes_for :user
end 

Trasy -- zwykłe rzeczy dla modelu członka.

resources :members
#maybe make a new path for New signups, but for now its new_member_path

Controller -- you have to build_user for nested attributes

#controllers/members_controller.rb
def new
    @member = Member.new
    @member.build_user
end

def create
    #... standard controller stuff
end

Views / members / new.html.erb

<h2>Sign up for new members!</h2>
<%= simple_form_for @member do |f| %>

    # user fields
    <%= f.fields_for :user do |u| %>
      <%= u.input :email, :required => true, :autofocus => true %>
      <%= u.input :password, :required => true %>
      <%= u.input :password_confirmation, :required => true %>
    <% end %>

    # member fields
    <%= f.input :name %>
    <%= f.input :tel %>
    <%= f.input :city %>

    <%= f.button :submit, "Sign up" %>
<% end %>

Chciałbym zaznaczyć, że nie ma potrzeby sięgania po gem nested_form; ponieważ wymóg jest taki, że użytkownik może należeć tylko do jednego rodzaju roli.

 26
Author: tw airball,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-16 03:41:18

Znalazłem sposób i jestem z tego całkiem zadowolony. Opiszę to tutaj dla innych.

Poszedłem z jednej klasy "użytkownik". Moim problemem było osiągnięcie spersonalizowanego procesu rejestracji dla każdego pseudo modelu.

Model/użytkownik.rb:

class User < ActiveRecord::Base
  devise :confirmable,
       :database_authenticatable,
       :lockable,
       :recoverable,
       :registerable,
       :rememberable,
       :timeoutable,
       :trackable,
       :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me, :role

  as_enum :role, [:administrator, :client, :member]
  validates_as_enum :role
  ## Rails 4+ for the above two lines
  # enum role: [:administrator, :client, :member]

end

Potem zaadaptowałem http://railscasts.com/episodes/217-multistep-forms i http://pastie.org/1084054 aby mieć dwie ścieżki rejestracji z nadpisanym kontroler:

Config / routes.rb:

get  'users/sign_up'   => 'users/registrations#new',        :as => 'new_user_registration'

get  'clients/sign_up' => 'users/registrations#new_client', :as => 'new_client_registration'
post 'clients/sign_up' => 'users/registrations#create',     :as => 'client_registration'

get  'members/sign_up' => 'users/registrations#new_member', :as => 'new_member_registration'
post 'members/sign_up' => 'users/registrations#create',     :as => 'member_registration'

Controllers / users / registrations_controller.rb:

Stworzyłem klasę kreatora, która zna pola do walidacji na każdym kroku

class Users::RegistrationsController < Devise::RegistrationsController

    # GET /resource/sign_up
    def new
        session[:user] ||= { }
        @user = build_resource(session[:user])
        @wizard = ClientRegistrationWizard.new(current_step)

        respond_with @user
    end

    # GET /clients/sign_up
    def new_client
        session[:user] ||= { }
        session[:user]['role'] = :client
        @user = build_resource(session[:user])
        @wizard = ClientRegistrationWizard.new(current_step)

        render 'new_client'
    end

    # GET /members/sign_up
    def new_member
      # same
    end

    # POST /clients/sign_up
    # POST /members/sign_up
    def create
        session[:user].deep_merge!(params[:user]) if params[:user]
        @user = build_resource(session[:user])
        @wizard = ClientRegistrationWizard.new(current_step)

        if params[:previous_button]
            @wizard.previous
        elsif @user.valid?(@wizard)
            if @wizard.last_step?
                @user.save if @user.valid?
            else
                @wizard.next
            end
        end

        session[:registration_current_step] = @wizard.current_step

        if @user.new_record?
            clean_up_passwords @user
            render 'new_client'
        else
            #session[:registration_current_step] = nil
            session[:user_params] = nil

            if @user.active_for_authentication?
                set_flash_message :notice, :signed_up if is_navigational_format?
                sign_in(:user, @user)
                respond_with @user, :location => after_sign_up_path_for(@user)
            else
                set_flash_message :notice, :"signed_up_but_#{@user.inactive_message}" if is_navigational_format?
                expire_session_data_after_sign_in!
                respond_with @user, :location => after_inactive_sign_up_path_for(@user)
            end
        end

    end

    private

    def current_step
        if params[:wizard] && params[:wizard][:current_step]
            return params[:wizard][:current_step]
        end
        return session[:registration_current_step]
    end

end

A moje poglądy to:

  • new.rb
  • new_client.rb wraz z częściową zgodnie z krokiem kreatora:
    • _new_client_1.rb
    • _new_client_2.rb
  • new_member.rb łącznie z częściowym według czarodzieja krok:
    • _new_member_1.rb
    • _new_member_2.rb
 18
Author: ddidier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-20 01:09:29

Co się stało? Po prostu uruchom rails g devise:views [model_name], Dostosuj każdy formularz rejestracyjny i w config/initializer/devise.rb po prostu umieść config.scoped_views = true.

 6
Author: Hauleth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-27 22:01:26