Сидя в Москве (как тут у вас многолюдно :), нашел время на написание серии статей по Rails.
Сегодняшняя тема навеяна печальным сообщением. Итак моя задача: показать как можно легко сделать авторизацию в Ruby on Rails. Задача новичков прочитать и попробовать, задача не новичков прочитать и написать как сделать лучше и/или указать на ошибки.
Использованные инструменты:
Стандартные операции:
Для авторизации в RoR существует куча плагинов. Я буду использовать restful-authentication.
Установка достаточно стандартна:
Теперь нужно создать модель пользователя, в которой будет храниться логин пароль и другие пользователь-related данные. Так же понадобиться два контроллера. Один для регистрации, а другой для логина/логаута. Пусть модель пользователя будет user, а контроллер для логина логаута sessions, тогда выполнив такую команду:
плагин все сделает за нас. У этого генератора есть несколько опций, например --include-activation, которая добавит активацию пользователя по e-mail. За более подробной информацией рекомендую обратиться к документации.
Генератор создаст два контроллера users и sessions, модель user, миграцию для модели user, записи в config/routes.rb и пару виюх которые скорей всего вы сразу же замените своими.
Роуты выглядят следующим образом:
Как видно все довольно хорошо вписывается в REST:
Я рекомендую с помощью опций роутов(введенных не так давно, не помню с какой версии) :only и :except, отредактировать запись map.resources :users (map.resources :users, :except => [:edit, :update, :destroy], for example). Например редактирование лучше перенести в отдельный роут: map.resource :profile, (редактирование в таком случае будет выглядить так: /profile/edit), так как скорей всего в вашем приложении одни пользователи других редактировать не должны.
Посмотрим на модель app/models/user.rb:
В принципе ничего интересного разве что, мне не совсем нравится, что логином выступает не e-mail. Чтобы это поправить нужно сдеать следующее: удалить из миграции db/migrate/xxxx_users.rb запись t.column :login, :string, :limit => 40. Модель пользователя сделать такой:
Файл app/views/users/new.html.erb тоже придеться изменить:
Все готово! Осталось выполнить миграции и запустить проект.
Для полноты можно добавить рутовый роут. Генерация рутового контроллера:
в config/routes.rb добавить:
Добавить лайтаут (app/views/layouts/application.html.erb):
Некоторые пояснения. В контроллере/виюхе «залогиненность» нужно проверять функцией logged_in? (true/false) доступ к пользователю который сейчай авторизован осуществляется через current_user. Готовый проект, в котором есть несколько исправлений не отраженных в статье.
Сегодняшняя тема навеяна печальным сообщением. Итак моя задача: показать как можно легко сделать авторизацию в Ruby on Rails. Задача новичков прочитать и попробовать, задача не новичков прочитать и написать как сделать лучше и/или указать на ошибки.
Использованные инструменты:
- Ruby 1.8.6
- Mac OS X 10.5.6
- Rails 2.2.2
- Mongrel 1.1.5
- MySQL 5.0.51b
Стандартные операции:
rails auth -d [любимая БД]
cd auth
rm public/index.html
[отредактировать config/database.yml]
rake db:create
Для авторизации в RoR существует куча плагинов. Я буду использовать restful-authentication.
Установка достаточно стандартна:
script/plugin install git://github.com/technoweenie/restful-authentication.git
Теперь нужно создать модель пользователя, в которой будет храниться логин пароль и другие пользователь-related данные. Так же понадобиться два контроллера. Один для регистрации, а другой для логина/логаута. Пусть модель пользователя будет user, а контроллер для логина логаута sessions, тогда выполнив такую команду:
script/generate authenticated user sessions
плагин все сделает за нас. У этого генератора есть несколько опций, например --include-activation, которая добавит активацию пользователя по e-mail. За более подробной информацией рекомендую обратиться к документации.
Генератор создаст два контроллера users и sessions, модель user, миграцию для модели user, записи в config/routes.rb и пару виюх которые скорей всего вы сразу же замените своими.
Роуты выглядят следующим образом:
Copy Source | Copy HTML<br/>ActionController::Routing::Routes.draw do |map|<br/> map.logout '/logout', :controller => 'sessions', :action => 'destroy'<br/> map.login '/login', :controller => 'sessions', :action => 'new'<br/> map.register '/register', :controller => 'users', :action => 'create'<br/> map.signup '/signup', :controller => 'users', :action => 'new'<br/> map.resources :users<br/> map.resource :session<br/>end <br/>
Как видно все довольно хорошо вписывается в REST:
sessions/new [GET] форма логина
sessions [POST] авторизация
sessions [DELETE] logout
users/new [GET] форма регистрации
users [POST] регистрация
Я рекомендую с помощью опций роутов(введенных не так давно, не помню с какой версии) :only и :except, отредактировать запись map.resources :users (map.resources :users, :except => [:edit, :update, :destroy], for example). Например редактирование лучше перенести в отдельный роут: map.resource :profile, (редактирование в таком случае будет выглядить так: /profile/edit), так как скорей всего в вашем приложении одни пользователи других редактировать не должны.
Посмотрим на модель app/models/user.rb:
Copy Source | Copy HTML<br/>require 'digest/sha1'<br/> <br/>class User < ActiveRecord::Base<br/> include Authentication<br/> include Authentication::ByPassword<br/> include Authentication::ByCookieToken<br/> <br/> validates_presence_of :login<br/> validates_length_of :login, :within => 3..40<br/> validates_uniqueness_of :login<br/> validates_format_of :login, :with => Authentication.login_regex, :message => Authentication.bad_login_message<br/> <br/> validates_format_of :name, :with => Authentication.name_regex, :message => Authentication.bad_name_message, :allow_nil => true<br/> validates_length_of :name, :maximum => 100<br/> <br/> validates_presence_of :email<br/> validates_length_of :email, :within => 6..100<br/> validates_uniqueness_of :email<br/> validates_format_of :email, :with => Authentication.email_regex, :message => Authentication.bad_email_message<br/> <br/> attr_accessible :login, :email, :name, :password, :password_confirmation<br/> <br/> def self.authenticate(login, password)<br/> return nil if login.blank? || password.blank?<br/> u = find_by_login(login.downcase) # need to get the salt<br/> u && u.authenticated?(password) ? u : nil<br/> end<br/> <br/> def login=(value)<br/> write_attribute :login, (value ? value.downcase : nil)<br/> end<br/> <br/> def email=(value)<br/> write_attribute :email, (value ? value.downcase : nil)<br/> end<br/>end <br/>
В принципе ничего интересного разве что, мне не совсем нравится, что логином выступает не e-mail. Чтобы это поправить нужно сдеать следующее: удалить из миграции db/migrate/xxxx_users.rb запись t.column :login, :string, :limit => 40. Модель пользователя сделать такой:
Copy Source | Copy HTML<br/>require 'digest/sha1'<br/> <br/>class User < ActiveRecord::Base<br/> include Authentication<br/> include Authentication::ByPassword<br/> include Authentication::ByCookieToken<br/> <br/> validates_format_of :name, :with => Authentication.name_regex, :message => Authentication.bad_name_message, :allow_nil => true<br/> validates_length_of :name, :maximum => 100<br/> <br/> validates_presence_of :email<br/> validates_length_of :email, :within => 6..100<br/> validates_uniqueness_of :email<br/> validates_format_of :email, :with => Authentication.email_regex, :message => Authentication.bad_email_message<br/> <br/> attr_accessible :email, :name, :password, :password_confirmation<br/> <br/> def self.authenticate(login, password)<br/> return nil if login.blank? || password.blank?<br/> u = find_by_email(login.downcase) # need to get the salt<br/> u && u.authenticated?(password) ? u : nil<br/> end<br/> <br/> def email=(value)<br/> write_attribute :email, (value ? value.downcase : nil)<br/> end<br/>end <br/>
Файл app/views/users/new.html.erb тоже придеться изменить:
<h1>Sign up as a new user</h1><br><% @user.password = @user.password_confirmation = nil %><br><br><%= error_messages_for :user %><br><% form_for :user, :url => users_path do |f| -%><br><br><p><%= label_tag 'email' %><br/><br><%= f.text_field :email %></p><br><br><p><%= label_tag 'password' %><br/><br><%= f.password_field :password %></p><br><br><p><%= label_tag 'password_confirmation', 'Confirm Password' %><br/><br><%= f.password_field :password_confirmation %></p><br><br><p><%= label_tag 'name' %><br/><br><%= f.text_field :name %></p><br><br><p><%= submit_tag 'Sign up' %></p><br><% end -%><br><br>* This source code was highlighted with Source Code Highlighter.
Все готово! Осталось выполнить миграции и запустить проект.
Для полноты можно добавить рутовый роут. Генерация рутового контроллера:
script/generate controller home index
в config/routes.rb добавить:
map.root :controller => 'home'
Добавить лайтаут (app/views/layouts/application.html.erb):
<html><br> <head><br> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /><br> <title>auth demo</title><br> </head><br><body><br> <%= render :partial => 'users/user_bar' %><br> <%= yield %><br></body><br></html><br><br>* This source code was highlighted with Source Code Highlighter.
Некоторые пояснения. В контроллере/виюхе «залогиненность» нужно проверять функцией logged_in? (true/false) доступ к пользователю который сейчай авторизован осуществляется через current_user. Готовый проект, в котором есть несколько исправлений не отраженных в статье.