Skocz do zawartości

Witaj na forum webmasterów Webax.pl.

Wyświetl nową zawartość

Ruby on Rails - alternatywa PHP - część siódma - logowanie i wylogowywanie


  • Zaloguj się, aby dodać odpowiedź
Brak odpowiedzi do tego tematu
Soanvig
Soanvig

    Początkujący

  • Użytkownik
  • PipPipPip
  • 114 postów
#1

Napisano 26 grudzień 2012 - 13:33

Witam was po długiej, bardzo długiej przerwie. Mam nadzieję, że chociaż część z was próbowała sama coś kodzić w Railsach. Jeśli tak jak ja, zrobiliście sobie przerwę, to przejrzyjcie na szybko pozostałe części tutoriala, żeby sobie co nieco przypomnieć.

Ostatnio skończyliśmy rejestrację (w ostatniej części przed chwilą dodałem walidację hasła [na jego obecność/minimalną długość] i naprawiłem poważny błąd z przekierowywaniem w metodzie new). W tej części - jednej z ostatnich części wstępu do RoR - stworzymy logowanie i wylogowywanie.

Zacznijmy od metody new. Sprawdziliśmy, czy rejestracja się udała - jeśli tak, użytkownik powinien zostać od razu zalogowany na swoje konto i przekierowany do panelu użytkownika. Panel użytkownika postanowiłem umieścić jako metodę start (moja logika wygląda następująco - użytkownik chce wejść na swoje konto, więc otwiera stronę główną. Ale nie jest zalogowany, więc zostaje przekierowany na rejestrację [mógłby być przekierowany na logowanie, ale musiałbym zmieniać koncepcję zawartą we wcześniejszych częściach] i wyświetla mu się też opcja zalogowania. Loguje się i wraca na swoje stronę główną - na swoje konto zarazem).

Czy user jest zalogowany sprawdzamy za pomocą sesji - każdy user posiada unikalną dla siebie sesję. Jeśli jest ona zdefiniowana i coś zawiera, user jest zalogowany. My w sesji zawrzemy ID użytkownika (automatyczne pole w bazie danych, każdy kolejny wpis w bazie posiada ID większe o 1 od poprzedniego - zupełnie jak w dzienniku obecności). Standardową praktyką przy pisaniu aplikacji webowych jest - na każdy wszelki wypadek - nie przechowywanie istotnych danych. I dlatego w sesji nie będziemy trzymać hasła (haszu) użytkownika, które defakto nie jest nam do niczego potrzebne. Tak więc wróćmy do metody new:
def newredirect_to :action => "start" if session[:user_id]if params["user"]require 'digest/sha2'password = Digest::SHA2.new << params["user"]["password"]data = {"username" => params["user"]["username"],"password" => password,"email" => params["user"]["email"],"register_date" => DateTime.now.to_date}@save = User.new(data)if @save.save# kod logowania i przekierowanieendend
I po sprawdzeniu, czy zapis do bazy się udał, dodajmy wspomniane logowanie i przekierowanie:
if @save.savesession[:user_id] = @save.idredirect_to :action => "start"end
Warto tutaj wspomnieć, że zmienna (instancja modelu) zawiera wszystkie pola wpisywane do bazy danych. Także to automatyczne pole - id. Oprócz zapisania w sesji identyfikatora wykonujemy standardowe przekierowanie. Podążając za działaniem skryptu przekierujmy się i my do metody start:
def startredirect_to :action => "new" if !session[:user_id]end
Teoretycznie już nic nie musimy dopisywać - jeśli user jest zalogowany, nie nastąpi przekierowanie i zostanie wyświetlony widok. Ale żeby użytkownik coś wiedział o swoim koncie, wyświetlimy mu jego ID zawarte w sesji - odciążymy w ten sposób bazę danych, bo nie będziemy nic z niej już pobierać. Dopiszmy więc zmienną, aby ją wyświetlić w widoku:
@id = session[:user_id]
... i przejdźmy do widoku metody start. Oto już gotowy widok:
<h1>User account panel</h1><p>Your user ID: <%= @id %></p><p><a href="/account/logout">Logout</a></p>
Generalnie cudów nie ma - nagłówek, wyświetlanie ID i link do wylogowania się. I znowu podążając za skryptem/użytkownikiem przejdźmy do metody logout.

Logika jest następująca - jeśli użytkownik zalogowany, zniszcz jego sesję (rozumiemy przez to ustawienie jest sesji na wartość absolutnie żadną, czyli nil), przekieruj do logowania. Spróbujcie sami napisać taki kod :)
ściągawka

No dobrze, powinien być bardzo podobny do mojego. Skoro nas przekierowuje do logowania, zróbmy logowania - przy pisaniu kodu cały czas podążamy ścieżką jaką podąża user!
Jedyne co w logowaniu musimy na razie zawrzeć, to sprawdzenie czy użytkownik jest już zalogowany, a jeśli jest to przekierować go do start. Chyba umiecie to sami napisać, co? :-)
No dobrze, użytkownik nie jest zalogowany i chce się zalogować. Czyli musimy mu wyświetlić formularz. Tym jednak razem, nie użyjemy helpera, a nauczymy się budować formularze ręcznie. Okazuje się, że wystarczy nam sam HTML + jedna funkcja RoR.
Zbudujmy więc formularz, dopiszmy warunek dla POST w routes i zobaczmy, czy wysyłanie formularza działa.

Routing:
post "account/login" => "account#login"
- przypominam konstrukcję: metoda (HTTP) "adres żądany przez użytkownika" => "adres w skrypcie"

Formularz w widoku login
<h1>Sign in</h1><form method="POST" action="/account/login"><label for="user">User:</label><input type="text" name="login[username]" id="user"><br><label for="password">Password:</label><input type="password" name="login[password]" id="password"><br><input type="submit"></form>
Standardowy formularz HTML. Już spieszę z wyjaśnieniem parametru name. Dlaczego jego zawartość przypomina pole w tablicy? Jak wiemy, wszystkie parametry przesłane przez użytkownika są zawarte w zmiennej params. Przy pisaniu aplikacji Rails jest używany następujący schemat:
nazwa_formularza[nazwa_pola]
Wtedy, w kodzie interpretujemy to następująco:
params[nazwa_formularza][nazwa_pola]
Helper tworzenia formularzy używa takiej samej koncepcji.

No. To by było na tyle :) Teraz spróbujmy się zalogować w metodzie login:
redirect_to :action => "start" if session[:user_id]if params["login"]if user = User.find_by_username(params["login"]["username"])session[:user_id] = user.idredirect_to :action => "start"endend
Nowości nie ma, za wyjątkiem nowej operacji na modelu User. Kiedy poznałem ten system moje uwielbienie dla Rails podskoczyło o 100% i wspięło się na wyżyny niesamowitości. Mianowicie przy tworzeniu modelu i definiowaniu pól, Rails automatycznie tworzy metody ułatwiające wydobywanie danych z bazy. I tak, jeśli chcemy znaleźć użytkownika po jego username, wystarczy, że użyjemy metody find_by_username, jeśli po haśle (absurdalne, ale to tylko przykład) to find_by_password, a jeśli po automatycznym id to po prostu find.

Wiem, wiem - to nie wszystko. Ale spróbujmy się zalogować na wcześniej utworzone konto (wpisując poprawny username).
Nie da się zalogować? Dziwne, prawda? Czas wspomnieć o tej tajemniczej funkcji. Mianowicie każdy formularz musi mieć swój dynamiczny token do autoryzacji, który tworzymy dorzucając do formularza następującą linijkę:
<input name="authenticity_token" type="hidden" value="<%= form_authenticity_token %>">

Teraz powinno dać się zalogować (w każdym razie, ja mogę ^^). No, ale logowanie na sam nick jest kompletnie bez sensu. Dodajmy sprawdzanie poprawności hasła i oto jak wygląda cały kod logowania:
def loginredirect_to :action => "start" if session[:user_id]if params["login"]if user = User.find_by_username(params["login"]["username"])password = Digest::SHA2.new << params["login"]["password"]if password == user.passwordsession[:user_id] = user.idredirect_to :action => "start"endendendend
UWAGA: w części szóstej tutoriala - walidacja, został poprawiony błąd przy zapisywaniu danych do bazy (przy password pojawiła się konwersja na string: .to_s)

W ramach ćwiczeń możecie dorzucić sobie wyświetlanie różnych błędów w przypadku niepoprawnych danych :-)
Oprócz tego następujące rzeczy przeróbcie sami:
- usuwanie rekordu z bazy danych (usuwanie usera - użytkownik powinien mieć opcję usunięcia swojego konta, potwierdzoną hasłem)
- walidacja, czy użytkownik nie znajduje się przypadkiem w bazie danych (przy rejestracji) za pomocą validates_uniqueness_of :username w modelu
I niech Google będą wam pomocą. A ja wkrótce postaram się do tego systemu użytkowników coś dodać. Może jakąś administrację?

I co bardzo ważne: czytajcie nie tylko poradnik, ale też wszystkie posty pod nim. Mogą się tam znajdować cenne uwagi od bardziej doświadczonych programistów RoR, których nie przeniosłem do tutorialu!

Ostatnią rzeczą jaką musimy zrobić, aby skrypt był funkcjonalny, to wrzucić gdzieś link do logowania - według koncepcji będzie to w widoku rejestracji:
<a href="/account/login">Sign in!</a>

Gdybyście zauważyli jakieś błędy, bądź napotkali problemy - śmiało piszcie :-)
Nie bijcie mnie za tabulację, IPB coś chrzani ^^
  • 1

[font="Courier;"].oooooooo8....ooooooo......o......oooo...oooo.888.........o888...888o...888......8888o..88...888oooooo..888.....888..8..88.....88.888o88..........888.888o...o888.8oooo88....88...8888..o88oooo888....88ooo88.o88o..o888o.o88o....88..[/font]