Railsチュートリアル第７章で学んだこと

今回はユーザー登録ページを作りました。

Railsには良い機能があってデバッグ画面を開発画面に表示できるからとても楽。


今回ユーザー登録するためにルーティングに新たに追加した

resources :users

これを追加するだけでusersの様々なURLや名前付きルートが使えるようになる。

HTTPリクエスト	URL	アクション	名前付きルート	用途
GET	　　　　　　　/users	index	users_path	すべてのユーザーを一覧するページ
GET	　　　　　　　/users/1	show	user_path(user)	特定のユーザーを表示するページ
GET	　　　　　　　/users/new	new	new_user_path	ユーザーを新規作成するページ（ユーザー登録）
POST	　　　　　/users	create	users_path	ユーザーを作成するアクション
GET	　　　　　　　/users/1/edit	edit	edit_user_path(user)	id=1のユーザーを編集するページ
PATCH	　　　　　/users/1	update	user_path(user)	ユーザーを更新するアクション
DELETE	　　　　　/users/1	destroy	user_path(user)	ユーザーを削除するアクション


ただまだルーティングだけなのでコントローラーにも随時追加していくことになる。

ユーザーページを表示するには

users/1みたいにidのページを表示したいのでそのときはparams[:id]で取得することができる

なのでそのidのなめなどを表示するためにコントローラーに記述する

def show
  @user = User.find(params[:id])
end

これでidの情報を取ってくることができる。

また画像表示にはGravatarを使う。
Gravatarは無料のサービスで、プロフィール写真をアップロードして、指定したメールアドレスと関連付けることができる。

userヘルパーにメソッドを作って表示させることにする。

def gravatar_for(user)
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
end

また

def gravatar_for(user, size: 80)
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
みたいに大きさを指定したりできる。

ユーザー表示できるようになったので

次は登録ページを作った。

まずは登録ページでUserオブジェクトにデータ送信したりするために

def new
    @user = User.new
end

を記入することにする

そしてフォームを作る
 
＜％form_with(model: @user, local: true) do |f|　％＞
      
end

fオブジェクトは、HTMLフォーム要素（テキストフィールド、ラジオボタン、パスワードフィールドなど）に対応するメソッドが呼び出されると、@userの属性を設定するために特別に設計されたHTMLを返します

＜％= f.label :name %>
＜％= f.text_field :name %>

は

＜label for="user_name">Name</label>
＜input id="user_name" name="user[name]" type="text" />

のように生成される

あとはフォーム送信で失敗したときにエラーメッセージを表示させるために

まずはcreateコントローラーを作って成功のときと失敗の時を分ける

def create
    @user = User.new(params[:user])    # 実装は終わっていないことに注意!
    if @user.save
      # 保存の成功をここで扱う。
    else
      render 'new'
    end
  end

上のparams[:user]だとparamsハッシュ全体を初期化するという行為はセキュリティ上、極めて危険。
仮に管理者権限のカラムがあってそれを誰でも送信できるようになるとすると誰でも管理者権限が持てるということになってしまってとても危険なのでこの場合、paramsハッシュでは:user属性を必須とし、名前、メールアドレス、パスワード、パスワードの確認の属性をそれぞれ許可し、それ以外を許可しないようにしたいと考えてるなのでコントローラーに

private

def user_params
params.require(:user).permit(:name, :email, :password,                                 :password_confirmation)
end

そして先程のところを

@user = User.new(user_params)

直すと良い

あとはエラーメッセージをフォームに差し込む

ついでに失敗したときのテストも書いとく

test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
end
 
これはassert_no_differenceメソッドのブロック内でpostを使い、メソッドの引数には'User.count'を与えています。これはassert_no_differenceのブロックを実行する前後で引数の値（User.count）が変わらないことをテストしている。

あとはちゃんと登録できたときの処理を書く。

def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render 'new'
    end
end

また成功したときにフラッシュを表示したほうがわかりやすいので

flash[:success] = "Welcome to the Sample App!"をコントローラーに追加する

あとはビューページに追加する

＜% flash.each do |message_type, message| %>
 ＜div class="alert alert-＜%= message_type %>"><%= message %>＜/div>
＜% end %>

そして次は成功したときのテストを書く

test "valid signup information" do
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                         email: "user@example.com",
                                         password:              "password",
                                         password_confirmation: "password" } }
    end
    follow_redirect!
    assert_template 'users/show'
end

さっきとは逆でassert_differenceブロック内の処理を実行する直前と、実行した直後のUser.countの値を比較します。第二引数はオプションですが、ここには比較した結果の差異（今回の場合は1）を渡しますfollow_redirect!は、POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動するメソッドです。

またflashのビューへの記述は

＜%= content_tag(:div, message, class: "alert alert-#{message_type}") %>

ともかける

あとはSSLの設定やサーバーの設定などをやったこれはたぶんそれぞれ違うだろうからいずれやることになると思う

今後はログイン機能などを作っていくことになる