Jak zarządzać użytkownikami z Devise - Ruby on Rails

Przez:, Z dnia:

Ten tutorial zakłada, że już ukończyłeś:

  1. Path: Setting Things Up

Devise jest świetnym gemem, dzięki któremu zaoszczędzimy sporo pracy. Użyjemy go by dać uzytkownikom naszej strony możliwość tworzenia kont, edytowania profilów, logowania, wylogowywania, wysyłania przypomnień hasła, itd. Wszystko jest bezpieczne i łatwe do konfiguracji. Możemy ręcznie wdrożyć wszystkie funkcjonalności dostarczane przez Devise, ale nie będziemy tego robić. Powód jest dwojaki. Po pierwsze, to by zajęło dużo czasu i drugie, poziom dostosowania, który będziemy potrzebować dla prostego projektu nie jest aż taki wysoki. Dlatego też, standardowa konfiguracja Devise będzie okej.

Nota: Ten tutorial jest dłuższy niż zwykle, nie spiesz się.

Krok 1: Przeczytaj Github Devise i Dodaj gem Devise

Przejdź do strony github Devise. Polecam przeczytać dokumentacje. Znajduje się tam wszysko czego potrzebujesz wiedzieć. W przyszłych tutorialach będziemy dostosowywać Devise, więc będziemy musieli wrócić do tej strony. Na obecną chwilę, nie spiesz się i sprawdź.

Na początek, potrzebujemy dodać Devise do naszego Gemfile. Gemfile jest listą wszystkich "wtyczek", czyli tak zwanych w społeczności Ruby "gemów". Gemy to samo zawierające się mini programy, które zbudowane są w taki sposób, że możemy dodać je bezbłędnie do naszej aplikacji. Devise jest jednym z tych "gemów". Dalej, otwórz Gemfile (powinieneś go znaleźć w folderze głównym aplikacji).

Gemfile

source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.0'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer',  platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0',          group: :doc

# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring',        group: :development

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use unicorn as the app server
# gem 'unicorn'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

# Use debugger
# gem 'debugger', group: [:development, :test]

Linijki, które zaczynają się od "#" są ignorowane przez oprogramowanie. Tym sposobem tworzymy komentarze w Ruby.

W Gemfile znajdziesz kilka gemów. Dodają one do aplikacji frameworki Javascript, jQuery, konfigurują bazę danych i więcej. Śmiało, dodaj gem Devise na spodzie naszego Gemfile:

Gemfile

gem 'devise'

Krok 2: Załaduj Aplikację

Musimy załadować naszą aplikację. Co znaczy, że "menedżer gemów" - nazwany bundler - pobierze niezbędne gemy z Internetu. Ten proces może zająć chwilę zależnie od wielkości gema i od tego czy robisz to po raz pierwszy.

Aby załadować aplikację, przejdź do terminalu, dalej do folderu aplikacji i odpal komendę:

$ bundle install

Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.

Krok 3: Stwórz plik Konfiguracyjny

Next, we need to generate a configuration file for Devise. In the terminal, run:

Następnie, potrzebujemy wygenerować plik konfiguracyjny Devise. Wpisz w terminalu:

$ rails generate devise:install
create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost:3000' }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:

       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

  5. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

Przeczytaj tą wiadomość uważnie. Mówi nam ona co dokładnie powinniśmy dalej zrobić.

Krok 4.1: Skonfiguruj pliki Środowisk

Spójżmy na to krok po kroku:

Krok 4.2: Zmień plik Aplikacji

1.  Wewnątrz folderu config/environments znajdują się trzy pliki. Po jednym dla każdego środowiska. Możemy je różnie skonfigurować.

Linijka z Devise mówi nam, że powinniśmy przejść do development.rb i test.rb.

config/environments/development.rb config/environments/test.rb

config.action_mailer.default_url_options = { host: 'localhost:3000' }

W środku naszego pliku production.rb  musimy umieścić rzeczywisty adres, który odpowiada naszej domenie. Jeżeli używasz Heroku, będzie to domena Heroku, na przykład: http://your-demo-application.com. Jeżeli już połączyłeś Heroku z własną domeną, będzie to http://www.custom-domain.com.

Jest to ważne, ponieważ wszystkie emaile Devise wysyłane do użytkowników - zresetowanie hasła, potwierdzenie konta, itd. - będą kierowane pod ten adres.

config/environments/development.rb config/environments/production.rb

config.action_mailer.default_url_options = { host: 'http://your-app-on-heroku.herokuapp.com' }

Krok 4.3: Stwórz strony statyczne

2. Jeżeli podążałeś za tutorialem "tworznie kontrolera stron statycznych" i go skończyłeś, omiń ten krok. W przeciwnym razie - wróć i zrób ten tutorial.

Krok 4.4: Wiadomości flash

3.  Aplikacje Rails używają wiadomości flash by powiadamiać nas o zdarzeniach. W przyszłości dużo będziemy ich używać, więc chcemy żeby wyglądały dobrze. Zaproponowany przez Devise przykład działa dobrze, ale wkrótce stanie się niewystarczający. Użyjemy innego kodu. Otwórz Twój wzorzec układu - jest to plik, którym będą owinięte wszystkie inne szablony. Przejdź do app/views/layouts/application.html.erb.

4. app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
<head>
    <title>Demo</title>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>

"<%= yield %>" zostanie zastąpiony naszymi szblonami, więc nie musimy pisać niezbędnego HTML, któy pojawi się na każdej stronie. Chcemy wyświetlić widomości tuż nad "yield":

<!DOCTYPE html>
<html>
<head>
    <title>Demo</title>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= csrf_meta_tags %>
</head>
<body>

<% flash.each do |key, value| %>
    <div class="alert alert-<%= key %> alert-dismissable">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
        <%= value %>
    </div>
<% end %>

<%= yield %>

</body>
</html>

Kod napiasny przez nas wykorzystuje TwitterBootstrap CSS. Dla instrukcji 4, używamy ostatniej wersji Rails, więc nic nie musimy robić. Tak samo dla instrukcji 5, nie będziemy robić żadnych zmian do widoków, więc to mamy skończone.

Krok 5: Skonfiguruj Email

Prawie skończyliśmy konfigurację. Ostatnią rzeczą do ustawienie jest system wysyłania emaili od naszej aplikacji, takich jak zrestartowanie hasła. Po pierwsze, otwórz plik początkowy (initializer) Devise:

config/initializers/devise.rb

config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'

Widzisz to? Zmień to na email, którego będziesz używał do wysyłanie emaili. W następnym kroku będziemy konfigurować system wysyłania emaili z Gmail. Jeżeli używasz Gmail, możesz wypełnić to pole z własnym emailem, jeżeli nie używasz, stwórz konto tutaj.

Ponadto, upewnij się że ten wiersz nie jest skomentowany.

config/initializers/devise.rb

config.secret_key = '1788ecf9deaa49646a8cf657d2c00faedd63033f8bfe3e16c7ddc0808502482a11b640c5b0a9f1089696477e7f3199a9861a1594422fccfa4222bb5d151b60fc'

Rozejszyj się po pliku. Jest w nim wiele ustawień Devise.

Krok 6: Zmień konfiguracje środowisk Rozwoju i Produkcji

Następnie, dodamy ustawienia do wysyłania faktycznych eamaili. W folderze config/environments zmodyfikujemy zarówno konfiguracje development jak i production.

/config/environments/development.rbalso

config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
      address: "smtp.gmail.com",
      port: 587,
      authentication: "plain",
      enable_starttls_auto: true,
      user_name: "your_email@gmail.com",
      password: "your_password"
}

/config/environments/production.rb

config.action_mailer.default_url_options =   { :host => 'your_app.herokuapp.com' }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
      address: "smtp.gmail.com",
      port: 587,
      authentication: "plain",
      enable_starttls_auto: true,
      user_name: "your_email@gmail.com",
      password: "your_password" 
}

Krok 7: Uruchom serwer Rails

To dobry czas by uruchomić ponownie naszą aplikację. Generator, który przed chwilą odpaliliśmy stworzył plik inicjalizujący. Wszystkie te pliki są ładowane podczas startowania aplikacji, więc jeżeli masz uruchomiony serwer, zastopuj go i uruchom ponownie. W oknie serwera kliknij "Control + c", potem wpisz:

$ rails server

Otwórz kolajną kartę termianla i wpisz:

$ rails generate devise user

Jak tylko naciśniesz enter, Rails stworzy kilka plików:

invoke  active_record
create    db/migrate/20140506090012_devise_create_users.rb
create    app/models/user.rb
invoke    test_unit
create      test/models/user_test.rb
create      test/fixtures/users.yml
insert    app/models/user.rb
route  devise_for :users

Krok 8: Przyjrzyj się Bazie Danych i odpal Rake Routes

Pierwszy plik to plik migracji: 20140506090012_devise_create_users.rb. Myśl o nim jak o instrukcji dla aplikacji, że czas na zmiany w bazie danych. Tak, po raz pierwszy będziemy używać naszej bazy danych. Otwórzmy ten plik i zobaczmy co jest w środku:

db/migrate/20140506090012_devise_create_users.rb

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    # add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

Uważaj! Od czasu do czasu, z jakiś nieznanych powodów, migracje są generowane bez rozszerzenia *.rb. Jeżeli nie jest ono obecne, migracje się nie uruchomią i będziesz miał z tym kłopoty. Dlatego też, jeżeli plik nie ma *.rb - dodaj to.

Dla celów tego tutorialu będziemy używać ustawień domyślnych. Jeżeli interesuje Cię zmiana ustwień, przejdź do strony github Devise i przeczytaj dokumentacje.

Następny dokument, który został stworzony, to model użytkownika. Model określa naturę naszych rejestrów. Z czasem stanie się bardziej jasnym jakie funkcje posiada nasz model. Na obecną chwilę, po prostu na niego spójrzmy, przczytajmy i zbadajmy jego strukturę.

app/models/user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end

Pierwsza i ostatni linijka to kolejno wiersz otwierający i zamykający naszej deklaracji użytkownika. Cały kod, który będzie dotyczył użytkownika, znajdzie się pomiędzy tymi wierszami. Devise automatycznie dodało kilka linijek.

# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

Te deklaracje nadają użytkjownikowi specjalne umiejętności. Użytkownicy mogą się zarejestrować (:registerable), zalogować (:database_authenticatable), odzyskać hasło (:recoverable), zostać zapamiętani przez przeglądarkę (:rememberable), my możemy zoabczyć kiedy są zalogowani lub nie (:trackable), i podczas rejestracji, możemy sprawdzić czy zapewnione przez nich dane są prawidłowe (:validatable).

Zostały także stworzone pliki testowe, ale ich nie będziemy na razie używać. Ostatnia linijka ("route devise_for :users") wskazuje na to, że Devise dokonał zmian w pliku routes.rb.

/config/routes.rb

Rails.application.routes.draw do
  devise_for :users

  root 'static_pages#home'

  #more lines of commented out code
end

Ta linijka kodu pozwala nam na używanie kilku ruterów do zarządzania użytkownikami. Zobaczmy jakie. W terminalu, z folderu aplikacji, wpisz:

bash

$ rake routes
        new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
           user_password POST   /users/password(.:format)      devise/passwords#create
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
                         PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
       user_registration POST   /users(.:format)               devise/registrations#create
   new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
                         PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy
                    root GET    /                              static_pages#home

Krok 9: Dodaj link do Wzorcowego Układu

Teraz, użyjmy tych ruterów i umieść w pliku wzorcowego układu link do strony logowania:

/app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
<head>
    <title>Demo</title>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= csrf_meta_tags %>
</head>
<body>

<% flash.each do |key, value| %>
<div class="alert alert-<%= key %> alert-dismissable">
    <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
    <%= value %>
</div>
<% end %>

<%= link_to 'Login', new_user_session_path %>

<%= yield %>

</body>
</html>

Widzisz jak użyliśmy pierwszej kolumny z listy ruterów "new_user_session", która kieruje do adresu "localhost:3000/users/sign_in" i do akcji "new" kontrolera devise/sessions. Zobaczmy jak to działa. Odpal swój serwer jeżeli obecnie nie masz uruchomionego:

bash

rails server

=> Booting WEBrick
=> Rails 4.1.0 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
[2014-05-07 11:06:08] INFO  WEBrick 1.3.1
[2014-05-07 11:06:08] INFO  ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0]
[2014-05-07 11:06:08] INFO  WEBrick::HTTPServer#start: pid=22386 port=3000

I otwórz przeglądarkę pod ardesem: localhost:3000.

devise missing migration error

Co to jest?! Pamiętasz jak tworzyliśmy użytkowników z Devise? Został wygenerowany plik migracyjny. Jednakże, jeszcze nie użyliśmy tego pliku do aktualizacji naszej bazy danych. Dlatego wyswietla się nam: Migrations are pending. To resolve this issue, run: bin/rake db:migrate RAILS_ENV=development. (Oczekujące migracje. By rozwiązać ten problem, odpal: bin/rake db:migrate RAILS_ENV=development.). Śmiało, uruchom "migrację" i napraw to. Otwórz nowy termianal i przejdź do aplikacji. Na Mac, możesz łatwo przejść do nowej karty klikając command + t, na linuksie ctrl + shift + t.

bash

$ rake db:migrate

== 20140506090012 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0040s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0014s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0008s
== 20140506090012 DeviseCreateUsers: migrated (0.0064s) =======================

Wróć do przeglądarki i odśwież.

devise login screen 1 devise login screen 2 devise login screen 3 devise login screen 4

Krok 10: Dodaj Rejestrację i Logowanie

Wspaniale! Możemy się teraz zarejestrować i zalogować. Prawie skończyliśmy ten tutorial. Wszystko czego teraz potrzebujemy to możliwość wylogowania. Otwórzmy jeszcze raz plik application.html.erb i zmieńmy trochę nasz link. Usuń: <%= link_to 'Login', new_user_session_path %> i zastąp to poniższym kodem:

/app/views/layouts/application.html.erb

<% if current_user %>
    <%= link_to 'Logout', destroy_user_session_path, method: :delete %>
<% else %>
    <%= link_to 'Login', new_user_session_path %>
<% end %>

Jeżeli odświeżysz stronę, powinieneś zobaczyć link do wylogowania. Sprawdź czy działa.

devise logout screen 1 devise logout screen 2

Zwróć uwagę na to, jak używamy "current_user". Tej metody możemy używać dzięki Devise. Jeżeli użytkownik jest zalogowany, current_user zwróci jego rekord. Możemy napisać kod w szblonie <%= current_user.email %>. Problem jest taki, że jeśli użytkownik nie jest zalogowany, current_user zwróci "nil" i kod <%= current_user.email %> będzie wyglądał tak: <%= nil.email %>, zepsuje on stronę. Dlatego też, powinniśmy do owinąć w warunek, który sprawdza czy current_user jest obecny, czyli czy jest zalogowany.

/app/views/layouts/application.html.erb

<% if current_user %>
    Welcome <%= current_user.email %> <%= link_to 'Logout', destroy_user_session_path, method: :delete %>
<% else %>
    <%= link_to 'Login', new_user_session_path %>
<% end %>

Pobaw się tym kodem. Jeżeli skonfigurowałeś juz email, Twoja aplikacjia powinna wysłać maile z prośbą o zresetowanie hasła.

Krok 11: Dodaj zmiany do Git i zrób Deploy do Heroku

Na konieć, dodaj zmiany do git i zrób deploy do Heroku:

bash

$ git add .
$ git commit -m "added devise users"

[master c8666a9] added devise
 9 files changed, 250 insertions(+), 29 deletions(-)
 create mode 100644 app/models/user.rb
 create mode 100644 db/migrate/20140506090012_devise_create_users.rb
 create mode 100644 db/schema.rb
 create mode 100644 test/fixtures/users.yml
 create mode 100644 test/models/user_test.rb
$ git push
$ git push heroku master

Po udanym wypchnięciu zmian, musisz zrobić migracje na Heroku.

$ heroku run rake db:migrate

Możesz się pochwalić. Posiadasz już działający system uwierzytelnienia. Czas na zbudowanie czegoś wspaniałego!

Musisz się zalogować by móc oznaczyć tutorial jako ukończony żeby śledzić swój postęp



Komentarze

  • Z dnia: Brunitob napisał:

    Such a wonderful guide!!!
  • Z dnia: Brunitob napisał:

    I had a minor issue when deploying to heroku, logout didn´t work. I solved -> http://stackoverflow.com/a/23317324
  • Z dnia: Mayurkumar napisał:

    thank you very much for such a wonderfull guide..

  • Z dnia: nate napisał:

    Lots of tutorials are great for diving deep and learning. These are great for building. Love it! I am wondering how to safely push to an open source repository like github if the email password is in the production.rb and development.rb files? Can't wait to work with these more.

  • Z dnia: COConsulting napisał:

    @nate I use the Figaro gem to help hide passwords when pushing my code to a public repository like github.

  • Z dnia: COConsulting napisał:

    I was a little misled by the title of this tutorial. It would be better titled "How to support users with Devise", or "How to allow users with Devise". The current title of, "How to manage users with Devise" made me think that this would be a tutorial showing how you can actually manage the users on your website using Devise. This is something that I am trying to implement on my site. I have Devise working and users are able to signup, login, update their profile, etc. And I even have multiple security levels (one being admins). Now, I want to allow a user that is an admin the ability to manage the other users on the site to reset passwords, or update the client's information. Unfortunately, that is not what this tutorial does.

    Other than a misleading title, it was a very thorough tutorial. Thank you.

Dodaj komentarz

Możesz się zalogować by skomentować