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ę!
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:
- dla każdego użytkownika Utwórz tabelę w bazie danych i odpowiedni model.
- 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
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.
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
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
.
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