RailsでHamlとRSpec

バージョン情報

$ ruby -v
ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
$ rails -v
Rails 3.1.1
Gem Version
https://github.com/indirect/haml-rails 0.3.4
https://github.com/rspec/rspec-rails 2.7.0

Railsアプリケーションを生成する

$ rails new rails_haml --skip-test-unit

RSpecを使いたいので,--skip-test-unitで単体テストを生成しない(-TでもOK).

Gemfileに以下を追加する.

gem "haml-rails"
group :test, :development do
  gem "rspec-rails", "~> 2.6"
end

gemをインストールする.

$ bundle install

最初にnewしたときにできたerbファイルをhamlにする.

$ cd app/views/layouts/
$ mv application.html.erb application.html.haml
$ emacs application.html.haml

置き換える内容はこちら

/ app/views/layouts/application.html.haml
!!!
%html
  %head
    %title RailsDeviseOmniauth
    = stylesheet_link_tag    "application"
    = javascript_include_tag "application"
    = csrf_meta_tags
  %body
    = yield

(これはhttp://html2haml.heroku.com/を利用して生成)

コントローラを生成する.

$ rails generate controller home index
      create  app/controllers/home_controller.rb
       route  get "home/index"
      invoke  haml
      create    app/views/home
      create    app/views/home/index.html.haml
      invoke  helper
      create    app/helpers/home_helper.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/home.js.coffee
      invoke    scss
      create      app/assets/stylesheets/home.css.scss

index.html.hamlができている.

Railsでユーザ認証(Devise)

バージョン情報

$ ruby -v
ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
$ rails -v
Rails 3.1.1
Gem Version
https://github.com/plataformatec/devise v1.4.9

Gemfile

Gemfileに追加する.

gem 'devise'

bundle installする.

$ bundle install

Deviseの導入と設定

Deviseをinstallする

$ 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. Setup default url options for your specific environment. Here is an
     example of development environment:

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

     This is a required Rails configuration. In production it must be 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 Rails 3.1 on Heroku, 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.

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

config/environments/developer.rbに設定を追加する*1

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

User(Model)の生成

Userを生成する.

$ rails generate devise user
      invoke  active_record
      create    db/migrate/20111112182038_devise_create_users.rb
      create    app/models/user.rb
      insert    app/models/user.rb
       route  devise_for :users

dbを生成する.

$ rake db:migrate
==  DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
   -> 0.0096s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0009s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0008s
==  DeviseCreateUsers: migrated (0.0116s) =====================================

Viewの生成

$ rails generate devise:views
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/devise/mailer
      create    app/views/devise/mailer/confirmation_instructions.html.erb
      create    app/views/devise/mailer/reset_password_instructions.html.erb
      create    app/views/devise/mailer/unlock_instructions.html.erb
      create    app/views/devise/shared
      create    app/views/devise/shared/_links.erb
      invoke  form_for
      create    app/views/devise/confirmations
      create    app/views/devise/confirmations/new.html.erb
      create    app/views/devise/passwords
      create    app/views/devise/passwords/edit.html.erb
      create    app/views/devise/passwords/new.html.erb
      create    app/views/devise/registrations
      create    app/views/devise/registrations/edit.html.erb
      create    app/views/devise/registrations/new.html.erb
      create    app/views/devise/sessions
      create    app/views/devise/sessions/new.html.erb
      create    app/views/devise/unlocks
      create    app/views/devise/unlocks/new.html.erb

アプリケーションの作成

認証の対象となるアプリケーションを作成する.

$ rails generate controller home index

routes.rbに追加

root :to => "home#index"

認証の設定

アプリケーションに認証をかける

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  before_filter :authenticate_user!
  def index
  end
end

レイアウトの設定

アプリケーションのレイアウトを設定し,ログアウトなどができるようにする.

/ app/views/layouts/home.html.haml
!!!
%html
  %head
    %title RailsDeviseOmniauth
    = stylesheet_link_tag    "application"
    = javascript_include_tag "application"
    = csrf_meta_tags
  %body{:class => params[:controller]}
    %header
      - flash.each do |name, msg|
        = content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String)
      %nav
        = current_user.email
        %ul
          - if user_signed_in?
            %li
              = link_to('Logout', destroy_user_session_path, :method=>'delete')
          - else
            %li
              = link_to('Login', new_user_session_path)
          - if user_signed_in?
            %li
              = link_to('Edit account', edit_user_registration_path)
          - else
            %li
              = link_to('Sign up', new_user_registration_path)
      %article
        = yield
      %footer

スタイルの設定

/* app/assets/stylesheets/application.css */
header nav ul {
  list-style: none;
  margin: 0 0 2em;
  padding: 0;
  li {
    display: inline; } }

#flash_notice, #flash_alert {
  padding: 5px 8px;
  margin: 10px 0; }

#flash_notice {
  background-color: #CFC;
  border: solid 1px #6C6; }

#flash_alert {
  background-color: #FCC;
  border: solid 1px #C66; }

*1:本番環境のための設定はprooduction.rbに行う

Railsでユーザ認証2(rails+Devise+OmniAuth)

バージョン情報

$ ruby -v
ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]
$ rails -v
Rails 3.1.1
Gem Version
https://github.com/intridea/omniauth 1.0.0
https://github.com/intridea/omniauth-openid 1.0.1
http://rubygems.org/gems/oa-core 0.3.2

Gemfile

Gemfileに追加する.

gem 'omniauth'
gem 'omniauth-openid'
gem 'oa-core'

bundle installする.

$ bundle install

Initializer

Deviseにomniauthの設定をする*1

# config/initializers/devise.rb
Devise.setup do |config|
  config.omniauth :open_id
  config.omniauth :open_id, :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id'
# 以下省略

User

deviseを:omniauthableに設定し,OpenIDのアクセストークンからユーザを自動で作るためのメソッドを追加する.

# app/models/user.rb
class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable

  attr_accessible :email, :password, :password_confirmation, :remember_me

  def self.find_for_open_id_oauth(access_token, signed_in_resource=nil)
    email = access_token.info['email']
    if user = User.find_by_email(email)
      user
    else
      User.create!(:email => email, :password => Devise.friendly_token[0,20])
    end
  end
end

OpenIdのCallbackの設定

config/routes.rbのdevise_for :usersを次の通りに変更する.

devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

Callback用のコントローラ

Callback用のコントローラは次の通り*2

# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def open_id
    open_id_general('open_id')
  end

  def google
    open_id_general('google')
  end

  private

  def open_id_general(kind)
    @user = User.find_for_open_id_oauth(request.env["omniauth.auth"], current_user)

    if @user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => kind
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.#{kind}_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
end

OpenIdでログインするためのリンク

ログインのためのリンクは自動的に生成されるが,手動で追加したい場合は次の通り.

= link_to "sign in with yahoo", user_omniauth_authorize_path(:open_id, :openid_url => "http://yahoo.com")
= link_to "sign in with google", user_omniauth_authorize_path(:google)

*1:参考文献にあるように,FileSystemを渡すとエラーになる.おそらく,:storeを指定してハッシュで渡すべきものと推察する.

*2:if文でelseになった場合にsessionにデータを登録する理由は不明