2012年4月19日木曜日

Ruby on Rails3でdeviseの利用を中止

さて、過去3回にわたってスクラッチから認証のシステムを作成しました。
これで認証の理解はバッチリなので、いよいよdiviseを使った認証をおこなっていきたいと思います。 環境はruby-1.9.3-p0, rails3.2.2, sqlite3です。

と、ここまで記述したのですが、結局deviseは利用しないことにしました。
一週間くらい検証に時間を費やしたのですが、今の力量で使うには危険すぎると判断しました。
少しカスタマイズするだけで影響が大きく、自分で実装した方が安全だからです。

rails初心者にはあまり薦められないツールのような気がします。ブラックボックスすぎて怖いです。

そんなわけで、僕はrails初心者がdiviseを使用するのはおすすめしません。ページングのkaminariもそうだったのですが、rails3のデファクトで良いとされている ツールは正直汎用性が低すぎるのではないかという印象です。もっとrubyとrailsに慣れればそうでもないのかもしれませんけどね。
僕の設計がrailsに合ってないのが原因もあると思います。

しかし、railsは生産性の高い万能フレームワークのようにいわれていますが、思うところが多々あります。

その内容は今度まとめて書きます。

以上です。でわ。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2012年4月11日水曜日

Ruby on Rails3でdeviseを使う前準備その3ログアウト

さて、前回の記事では、ログインの仕組みを作成しました。今度はログアウトの仕組みを作成します。
この記事は前回の続きなので、前回を読んでいないと、多分理解できません。
環境はruby-1.9.3-p0, rails3.2.2, sqlite3です。

ルーティングの設定


  get "log_out" => "sessions#destroy", :as => "log_out" # 今回追加
  get "log_in" => "sessions#new", :as => "log_in"
  get "sign_up" => "users#new", :as => "sign_up"
  root :to => "users#new"
  resources :users
  resources :sessions

設定ができているかをrake routesコマンドで確認します。


     log_out GET    /log_out(.:format)           sessions#destroy
      log_in GET    /log_in(.:format)            sessions#new
     sign_up GET    /sign_up(.:format)           users#new
        root        /                            users#new
       users GET    /users(.:format)             users#index
             POST   /users(.:format)             users#create
    new_user GET    /users/new(.:format)         users#new
   edit_user GET    /users/:id/edit(.:format)    users#edit
        user GET    /users/:id(.:format)         users#show
             PUT    /users/:id(.:format)         users#update
             DELETE /users/:id(.:format)         users#destroy
    sessions GET    /sessions(.:format)          sessions#index
             POST   /sessions(.:format)          sessions#create
 new_session GET    /sessions/new(.:format)      sessions#new
edit_session GET    /sessions/:id/edit(.:format) sessions#edit
     session GET    /sessions/:id(.:format)      sessions#show
             PUT    /sessions/:id(.:format)      sessions#update
             DELETE /sessions/:id(.:format)      sessions#destroy
  

準備OKです。続いてsessions_controllerコントローラーにログアウト処理を実装します。

ログアウト処理


  def destroy
    session[:user_id] = nil
    redirect_to root_url, :notice => "Logged out!"
  end

以上で完了です。サーバーを起動して、http://localhost:3000/log_outにアクセスしましょう。
ログアウトされるはずです。
アプリケーションでは、viewでログイン、ログアウトの状態を切り替えられるようにすると良いでしょう。

さて、これで認証のコーディングは終わりです。
確かに、一度はくらいはスクラッチから認証の仕組みはつくっておいたほうが良さそうですね。
他の認証系のgemも同じような作りでしょうから。

僕が今回参考にしたのは
http://railscasts.com/episodes/250-authentication-from-scratch
です。

英語のサイトですが、この記事と組み合わせれば特に問題ないでしょう。

それでは、また。長い時間お疲れさまでした。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

Ruby on Rails3でdeviseを使う前準備その2ログイン

さて、前回の記事では、ユーザー登録の仕組みを作成しました。今度はログインの仕組みを作成します。
この記事は前回の続きなので、前回を読んでいないと、多分理解できません。
環境はruby-1.9.3-p0, rails3.2.2, sqlite3です。

コントローラーの作成


cd auth // プロジェクトフォルダへ移動

rails generate controller sessions new

sessions_controllerとsessions/view/new.html.erbのviewを作成します。

new.html.erbを変更

<h1>Log in</h1>
<%= form_tag sessions_path do %>
 <p>
   <%= label_tag :email %><br/>
   <%= text_field_tag :email, params[:email] %>
 </p>
 <p>
   <%= label_tag :password %><br/>
   <%= password_field_tag :password %>
 </p>
 <p><%= submit_tag %></p>
<% end %>

viewを作成。emailとパスワードの入力フィールドを表示します。

ルーティングの設定


  get "log_in" => "sessions#new", :as => "log_in" # 今回追加
  get "sign_up" => "users#new", :as => "sign_up"
  root :to => "users#new"
  resources :users
  resources :sessions # 今回追加
 

設定ができているかをrake routesコマンドで確認します。


      log_in GET    /log_in(.:format)            sessions#new
     sign_up GET    /sign_up(.:format)           users#new
        root        /                            users#new
       users GET    /users(.:format)             users#index
             POST   /users(.:format)             users#create
    new_user GET    /users/new(.:format)         users#new
   edit_user GET    /users/:id/edit(.:format)    users#edit
        user GET    /users/:id(.:format)         users#show
             PUT    /users/:id(.:format)         users#update
             DELETE /users/:id(.:format)         users#destroy
    sessions GET    /sessions(.:format)          sessions#index
             POST   /sessions(.:format)          sessions#create
 new_session GET    /sessions/new(.:format)      sessions#new
edit_session GET    /sessions/:id/edit(.:format) sessions#edit
     session GET    /sessions/:id(.:format)      sessions#show
             PUT    /sessions/:id(.:format)      sessions#update
             DELETE /sessions/:id(.:format)      sessions#destroy
  

準備OKです。続いてsessions_controllerコントローラーにログイン処理を実装します。

ログイン処理

class SessionsController < ApplicationController

  def new
  end
  
  def create
    user = User.authenticate(params[:email], params[:password])
    if user
      session[:user_id] = user.id
      redirect_to root_url, :notice => "Logged in!"
    else
      flash.now.alert = "Invalid email or passsword"
      render "new"
    end
  end
  
end

上記の処理ではユーザーデータが取得できた場合はセッションにユーザーIDを保存し、画面遷移します。
ユーザー情報がない場合は、エラーメッセージを表示しています。

Userクラス

コントローラーで宣言したUserのauthenticate処理を実装します。


  def self.authenticate(email, password)
    user = find_by_email(email)
    if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
      user
    else
      nil
    end
  end
  

メールと、ハッシュパスワードが等しい場合は、userオブジェクトを返しています。

さて、ここまでできたら、サーバーを起動して、http://localhost:3000/log_inにアクセスしましょう。
ミスがなければ画面が表示されるはずです。入力チェックと、正常入力を試してみてください。
loginが正常に働いて、画面遷移できれば成功です。

さて、次回はログアウトの仕組みを作成していきましょう。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

Ruby on Rails3でdeviseを使う前準備その1ユーザー登録

さて、前回の記事では、diviseを使う前に、railsで認証の仕組みを一度スクラッチから組むべきだというReadMeの内容を紹介しました。
そんなわけで今回は、railsで認証の仕組みをスクラッチから作成していこうと思います。
環境はruby-1.9.3-p0, rails3.2.2, sqlite3です。
この記事の対象者は、railsのド基礎を理解している人です。つまり、controllerでviewからのパラメーターを取得して、DBにデータを格納する流れがわかるレベルでOKです。中級者と上級者は帰ってください。僕が恥ずかしいからw

しかし、本当に覚えること多すぎじゃね、Rails。javaのEJBより敷居高いかも。

というわけでLet's start!!

プロジェクトの作成


rails new auth 

コントローラーの作成


cd auth // プロジェクトフォルダへ移動

rails generate controller users new

users_controllerとusers/view/new.html.erbのviewを作成します。

テーブルモデルの作成


rails generate model user email:string password_hash:string password_salt:string

emailはメールアドレスです。password_hashはパスワードハッシュのことです。意味はこういうこと。
password_saltはパスワードハッシュ値を作成する時に、パスワード文字列と共に用いられる任意の文字列のことです
なに言っているかわかね〜って人は認証のシステムを作る前に、セキュリティの勉強からはじめてください。

テーブルの作成


rake db:migrate

テーブルが作成されます。これで準備OK。続いて、コードを記述していきます。

UsersControllerを記述

# coding : utf-8
class UsersController < ApplicationController
  def new
    @user = User.new
  end
  
  def create
     @user = User.new(params[:user])
     if @user.save
      redirect_to root_url, :notice => "signed up!"
     else
       render "new"
     end
  end
end

createメソッドは、userのパラメーターを取得してDBの保存に成功したら、root_urlへ遷移し、メッセージを表示します。失敗した場合は、エラーメッセージと共にnew.html.erbを再表示します。

new.html.erbを変更

<h1>Sign Up</h1>
<%= form_for @user do |f| %>
 
 <!-- error msg -->
 <% if @user.errors.any? %>
   <ul>
     <% @user.errors.full_messages.each do |msg| %>
     <li><%= msg %></li>
     <% end %>
   </ul>
 <% end %>
 
 <!-- display field -->
 <p>
   <%= f.label :email %><br/>
   <%= f.text_field :email %>
 </p>
 <p>
   <%= f.label :password %><br/>
   <%= f.password_field :password %>
 </p>
 <p>
   <%= f.label :password_comfirmation %><br/>
   <%= f.text_field :password_comfirmation %>
 </p>
 <p><%= f.submit %></p>
<% end %>

viewを作成。emailとパスワード、パスワードの確認を表示します。保存失敗の場合のエラーメッセージも表示します。

ルーティングの設定


  get "sign_up" => "users#new", :as => "sign_up"
  root :to => "users#new"
  resources :users
  

getはHTTPメソッドです。=>は:controllerと:actionの短縮生です。:asはルート名です。詳しい説明はここが理解しやすいです。

設定ができているかをrake routesコマンドで確認します。


  sign_up GET    /sign_up(.:format)        users#new
     root        /                         users#new
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
     user GET    /users/:id(.:format)      users#show
          PUT    /users/:id(.:format)      users#update
          DELETE /users/:id(.:format)      users#destroy
  

はい準備OKです。続いてUserクラスを修正します。

Userクラス

必要なのは、パスワードのアクセサー、バリデーションの処理です。


  attr_accessor :password, :password_comfirmation
  
  validates email,
    :presence => true,
    :uniqueness => true
  validates password,
    :presence => true,
    :length => {:minimun => 7, maximum => 15}
  

メールは一意で入力必須。パスワードは、入力必須で7-15文字制限にします。

続いてパスワードの暗号化を行います。暗号化にはbcrypt-rubyを使います。Gemfileに記述してライブラリを利用できるようにします。


  vi Gemfile
  
  gem "bcrypt-ruby", :require => "bcrypt"

暗号化処理

続いて、暗号化処理を実装します。パスワードの暗号化はvalidationのチェックの終了後、つまりテーブルに保存する前におこないます。


  attr_accessor :password, :password_comfirmation
  before_save :encrypt_password
  
  validates email,
    :presence => true,
    :uniqueness => true
  validates password,
    :presence => true,
    :length => {:minimun => 7, maximum => 15}
  

暗号化処理を実装します。


  attr_accessor :password, :password_comfirmation
  before_save :encrypt_password
  
  validates :email,
    :presence => true,
    :uniqueness => true
  validates :password,
    :presence => true,
    :length => {:minimun => 7, :maximum => 15}

  def encrypt_password
    if password.present?
      self.password_salt = BCrypt::Engine.generate_salt
      self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
    end
  end
 

bcrypt-rubyの処理内容はここで確認できます。

さて、ここまでできたら、サーバーを起動して、http://localhost:3000/sign_upにアクセスしましょう。
ミスがなければ画面が表示されるはずです。入力チェックと、正常入力を試してみてください。
正常入力がうまくいったら、dbを確認してみましょう。

1|test@test.co.jp|$2a$10$BLJBZXyvzecoZJeiZrMYhOuZbRQJQDyESfMjrcwkofvB2UGGBvdPK|$2a$10$BLJBZXyvzecoZJeiZrMYhO|2012-04-11 06:29:23.361652|2012-04-11 06:29:23.361652

おお。見事に入力されていますね。暗号化も完璧です。

さて、次回はログインの仕組みを作成していきましょう。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

rails3でdeviseを使う。その1

ログイン画面を作るため、deviseを使うことにしました。
環境はこれまで通りruby1.9.2, rails3.0.10, sqlite3でやろうとしたのですが、ドキュメントを読むと、rails3.1以上にしてと記載されていました。

せっかくなので、railsの環境を最新にすることにする。

以下にメモ。

rubyを最新にする

利用予定のHerokuで、1.9.3-p0が利用できるようなのでこれを導入する。


rvm install ruby-1.9.3-p0

installが終了したら以下の手順を行います。


rvm list // installの確認

rvm use ruby-1.9.3-p0 // rubyを切り替える

rvm gemset create rails322 // gemsetを作成

rvm gemset list // 作成したgemsetがあることを確認する

rvm use 1.9.3-p0@rails322 // 作成したgemsetにする

gem install rails -v 3.2.2 // rails3.2.2をinstall

which rails // install場所を確認

rails -v // バージョンの確認

Rails 3.2.2 // ok

上記の作業を全て終えたら準備完了です。では、つづけてdeviseのinstallいきまっしょい。

devise install


gem install devise 

gem list // installの確認

devise (2.0.4)

さて、勉強用のアプリを作成します。test用のアプリを作成します。

rails new practice  // プロジェクト作成

適当に動作確認。次は、deviseをアプリで利用できるようにGemfileに追加。


vi Gemfile

gem 'devise'

これで準備OK。さあ、はじめようか!!

rails generate devise:install

実行すると、以下のメッセージが表示される。1-4までを手動で設定を行えとのことです。

$ 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 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.

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

上記はメモを残しておきます。Herokuにアップするとき、設定が必要みたいなので。

今回は開発環境だけなので、1-3を実施します。

設定が完了したら、モデルを作成します。

rails generate devise User

ファイルが作成されるので、コードをざっくりと目を通しておきます。よくわからないけど、OKw
DBを作成します。

rake db:migrate 

標準のviewを作成します。

rails generate devise:views 

app/views/devise以下に色々なファイルが生成されるのを確認します。rails serverでサーバーを立ち上げます。

http://localhost:3000/users/sign_inにアクセスすると、Sign inのページが表示されます。

これでOKと思いきや、カスタマイズ方法が全然わからん。
Readmeをあさっているとこんな表記かあった。

Starting with Rails?

If you are building your first Rails application, we recommend you to not use Devise. 
Devise requires a good understanding of the Rails Framework. 
In such cases, we advise you to start a simple authentication system from scratch, today we have two resources:

ざっくりいうと、rails初心者は、認証のシステムを一度最初から作って、仕組みを理解してから使え。とのこと

正論すぎますね。まったくその通り。
ということで今回のシステムではdeviseは使わずに、自分でスクラッチから作って利用することにします。

急がば回れ〜なのです。
んじゃ

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2012年4月9日月曜日

初心者のRuby on Rails3その1

どうも。ヘボRailsプログラマーです。

色々と悪戦苦闘しながら開発しています。というわけで、以下rails初心者(自分)が陥ったメモのまとめです。

普段他言語を使っている人はきっと同じようなミスをするんではないでしょうか。

controllerクラスにresponseというメソッドを作成することはできない

予約語なんですね。

Modelクラスにtypeという列名を作成してはいけない

これも予約語なんですね。

文字列の結合には+でなく << を使う


sql = "select * from test where id = " + id

上記のように+で文字列を連結すると処理は遅くなります。Stringオブジェクトの生成コストが高いようです。


sql = "select * from test where id = "
sql << id

<<かconcatが正解。<<が個人的には好みです。

条件分岐は極力シンプルに


if @obj.blank?
  somethig
end

上記のような処理は行数の無駄です。rubyらしく記述しましょう。


somethig if @obj.blank?

上記のように書けば一行ですっきり記述できます。

テキストエリアに入れたデータをviewで表示する


<%= simple_format @obj.text %>

simple_formatは、改行を< br /> にして出力してくれます。文字列は< p> < /p> で囲まれることにも注意してください。
スタイルシートでpでclassやidを指定している場合は、pのみでスタイルを変更できるように修正しましょう。

ハッシュの条件式はシンプルに


if !params[:test_id].blank?
  something
else 
  something
end

上記はよくあるパターンです。パラメーターのハッシュの値があるかどうかの判断。でも、blank?は不要です。
ハッシュは存在するキーがないとnil値を返します。そして、nilは条件式でfalseになります。
つまり、以下のようにするのが正解


if params[:test_id]
  something
else 
  something
end

どうや!blank?メソッドなんていらんのや。省エネやで!

とりあえず、最初のまとめはこんな感じです。rubyは初心者なんで思いっきり勘違いしているかもしれませんがw

pythonの次くらいに好みの言語になれそうな気がいまのとこしてます。
でわ。また。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2012年4月8日日曜日

Ruby on Rails3のページング処理でwill_paginateを使う

find_by_sqlを使うような複雑なsqlを利用しながら、rails3でページング処理をおこなったので以下にメモ。
環境はruby1.9.2,rails3.0.10

find_by_sqlを利用した複雑なSQLは、Kaminariのページング処理では対応できなかったので、will_paginateを使いました。あと注意して欲しいのは、kaminariとは共存できないことです。まあ、する必要ないんですどw

まずはプロジェクトで利用しているrvmにします。


rvm use 1.9.2@rails3010

内容をチェックします。


gem list

内容をチェックします。will_paginateがないことを確認してgemのinstall


gem install will_paginate --pre

インストール終了後に確認します。


gem list

will_paginate (3.0.pre4)

OK。さて、ではアプリケーションで利用できるようにします。アプリケーションフォルダに移動して、Gemfileを開きます。


vi Gemfile

gem 'will_paginate','3.0.pre4'

保存して、準備OKです。

さて、あとはfin_by_sqlを利用している箇所を以下のように書き換えます。


find_by_sql(sql)

↓

paginate_by_sql(sql, :page => pages, :per_page => 10)

このように記述すると、以下のようなsqlが走ります。


[sql] LIMIT 10 OFFSET 0

自動的にlimit offsetが追加されているのがわかります。つづいてviewに記述します。


<%= will_paginate @tests %>

ページングが必要なデータ量の場合、これでリンクが表示されます。便利ですね。

デザインを変えたい場合は、こちらから好みのcssをダウンロードしてdivでクラスを指定して使えばOKです。

kaminariを使うか、will_paginateを使うかは、仕様次第な気がします。しかし、個人的にはwill_paginateのほうが良いと感じました。実際、僕はwill_paginateを利用しています。

railsの進歩に応じて、色々なパターンを試してみるのが、結局は一番なのでしょう。

railsなだけに、アジャイルに適応しようってことですね。それでわ。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

Ruby on Rails3のページング処理でKaminariを使う

rails3でページング処理をおこなったので以下にメモ。
環境はruby1.9.2,rails3.0.10

rails3でページン処理を実装する場合、Kaminariというgemが標準らしいので使用してみました。

まずはプロジェクトで利用しているrvmにします。


rvm use 1.9.2@rails3010

内容をチェックします。


gem list

内容をチェックします。Kaminariがないことを確認してgemのinstall


gem install kaminari

インストール終了後に確認します。


gem list

kaminari (0.13.0)

OK。さて、ではアプリケーションで利用できるようにします。アプリケーションフォルダに移動して、Gemfileを開きます。


vi Gemfile

gem 'kaminari'

保存して、準備OKです。

続いて、Modelにページングの処理を記述します。


paginates_per 10

ページングの処理を使いたい適当なModelに上記のような設定を記述します。記述したらコントローラーから呼び出します。


@tests = Test.order("insert_date desc").page params[:page]

このように記述すると、以下のようなsqlが走ります。


SELECT "tests".* FROM "tests" ORDER BY insert_date desc LIMIT 10 OFFSET 0

自動的にlimit offsetが追加されているのがわかります。つづいてviewに記述します。


<%= paginate @tests %>

ページングが必要なデータ量の場合、これでリンクが表示されます。便利ですね。

しかし、このkaminariには致命的な欠点もあります。それは、find_by_sqlを使うような複雑なSQLには対応していないことです。
配列で取得してページングはできるのですが、limit offsetが利用できないので、一度に全ての データを取得しないといけないのです。これでは、現実的ではありません。
というわけで、find_by_sqlを使う場合は、他の方法でページングする必要があります。

とりあえず、今回はここまでです。でわ。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2012年4月7日土曜日

マージンの相殺

HTML5とCSS3でレイアウトを組み上げているとき、「マージンの相殺」の罠にはまりました。
display:blockを設定したsectionのボックスを入れ子にしたとき、内側のmargin-topの設定が反映されない現象です。

解決方法はこちらです。

結論を言うと、外側にpadding-top、内側にmargin-topを挟むことで解決できます。

「マージンの相殺」なんて名称がついていますが、ただのブラウザのバグですな。
ファミコンゲームのバグを裏技と信じていた純粋な子供時代を思い出しました。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2012年4月6日金曜日

railsアプリのテーブル設計で思ったこと

こんにちわ。初の本格的なrailsアプリの作成で、色々苦労しています。

現在開発中で特に強く感じたのは、railsを使う場合は、テーブル設計は極力railsの仕様の合わせるべきだということです。

テーブルを正規化して、ごちゃごちゃと複雑なSQLを組みあげるのは間違ってます。railsはあなたのsqlの腕前を披露する場ではありません。テーブルはrailsの仕様に合わせたテーブルに設計しなおすべきです。「設定より規約」なのです。

railsを使ったアプリのテーブル設計で大事になのことは、railsのコードでどう記述するかです。

特にjavaや.netで開発をしてきたWEBアプリエンジニアは要注意です。「これまでこうやってきた。なので、これが正しい。」という思い込みは捨ててください。海外ではその国の法律に従うように、railsではrailsの規約に従うのがベストです。

そんなこと無理だ。という人は、他のフレームワークを使うべきです。DjangoとかDjangoとか!

railsは良いフレームワークです。だたし、その代償を受け入れることも必要です。

とはいえ、全てをrailsの仕様に合わせるわけにもいきません。その辺りは設計者の腕のみせどころです。find_by_sqlを利用して組み上げたデータのページング処理等は、強引に実装するしかないでしょう。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加
Related Posts Plugin for WordPress, Blogger...