2011年9月2日金曜日

Rails3を初歩から学ぶ #14 アクセス制限してみよう

この一連のエントリは
Ruby on Rails 3 Tutorial: Learn Rails by Example (Addison-Wesley Professional Ruby Series)
で参考に学んだことを凝縮してお送りしています。

前回まででサインイン処理を実現しました。
が、認証せずに「http://localhost:3000/users/1」とするとアクセスできてしまいます。
認証済みユーザー以外はアクセスして欲しくないページには認証を事前に確認するようにしましょう。
spec/controller/users_controller_spec.rbを編集します。

describe "GET 'show'" do
describe "サインインしていなければアクセス禁止" do
before(:each) do
@user = Factory(:user)
end
it "サインインページにリダイレクトされること" do
get :show, :id => @user
response.should redirect_to(signin_path)
end
end #サインインしていなければアクセス禁止

describe "サインインしていればアクセス可能" do
before(:each) do
@user = Factory(:user)
controller.sign_in(@user)
end
it "should be successful" do
get :show, :id => @user
response.should be_success
end
it "正しいユーザーを表示していること" do
get :show, :id => @user
assigns(:user).should == @user
end
it "タイトルの検証" do
get :show, :id => @user
response.should have_selector("title", :content => @user.name)
end
end #サインインしていればアクセス可能
end #GET 'show'
赤字の部分を追加します。
既存の検証コードはbeforeブロックでサインインするようにしています。
そして今回新たにサインインしていないときはサインイン画面に遷移することを検証しています。では実装しましょう。
まずは認証済みかどうかをチェックして、認証していない場合はサインインページに飛ばす処理ですが、これは色々と使い回しそうなのでヘルパメソッドとして定義しておきます。
app/helpers/sessions_helper.rb に以下の2つのメソッド(public)を追加します。

def authenticate
deny_access unless signed_in?
end
def deny_access
redirect_to new_session_path, :notice => "サインインしてください"
end
signed_in?メソッドは前回実装したものでcookieの情報から認証状態をチェックします。
これでnilが返った場合はdeny_accessメソッドによりサインインページに飛ばしています。
ではこのヘルパを呼び出しましょう。
app/controller/users_controller.rbに以下の行を追加します。
before_filter :authenticate, :only => :show
これでshowアクション実行前に先ほど定義したauthenticateが呼ばれるようになります。
これでテストもパスするようになるので実際にサーバからサインインせずに
「http://localhost:3000/users/1」などとアクセスしてみてください。
サインインページに飛ばされます。

で、この状態で新規登録ページからユーザーを登録してみると、サインページに飛んでしまいます。実はまだユーザー登録時にサインインを処理していないので未認証状態なんですね。それはまあ良しとして問題はテストを実施してもNG0件なってしまうことです。
users_controller_spec.rbにてサインイン時に以下のような検査コードがあります。
response.should redirect_to(user_path(assigns(:user)))
これはサーバからusers/:idへのリダイレクトメッセージが返ることを検証しているもので、確かにこの検証からすればNGにはなりません。今、問題になっているのはリダイレクトしたらその先のbefore_filterで弾かれているからです。
というわけで新規ユーザーを登録したらサインイン済みになっているかどうかを検証するテストを追加しておきましょう。
spec/controller/users_controller_spec.rb の「POST create」の「登録に成功するケースの検証」のブロックに以下の検証コードを追加します。

it "新規登録成功時はサインイン済みとすること" do
post :create, :user => @attr
controller.should be_signed_in
end
RSpecではbool値を返すメソッドに対して「be_***」という検証用メソッドを自動で追加します。ここではsigined_inメソッドがtrueを返すことを期待しています。
このテストコードにより無事、NGが検出されるようになりました。
では対応しましょう。
といってもapp/controller/users_controller.rb のcreateアクションに下記赤字の1行を追加するのみです。


def create
@user = User.new(params[:user])
if @user.save
sign_in @user
flash[:success] = "登録に成功しました"
redirect_to @user
else
@title = "新規登録"
@user.password = ""
@user.password_confirmation =""
render 'new'
end
end
これで新規登録と同時にサインインした状態になるようにできました。



0 件のコメント:

コメントを投稿