Ⅵ~Ⅷ章では、ユーザ機能及びログイン機能を追加しています。
Ruby on Rails5 学習コースⅥ
・Userモデルとusersテーブルの作成
$ rails g model User name:string email:string $ rails db:migrate
・Userモデルとusersテーブルの作成
# (models/user.rb) validates :email, {uniqueness: true}
・ユーザ新規登録ページの作成
# (users/new.html.erb) <p>ユーザ名</p> <input name="name" value="<%= @user.name %>"> # 1行のフォームは<input>タグを使用する <input name="email" value="<%= @user.email %>"> # value属性にRubyのコードを埋め込む <input type="submit" value="新規登録">
・完成版
# (models/user.rb) validates :name, {presence: true} validates :email, {presence: true, uniqueness: true} # (routes.rb) get "users/index" => "users#index" get "signup" => "users#new" get "users/:id" => "users#show" post "users/create" => "users#create" get "users/:id/edit" => "users#edit" post "users/:id/update" => "users#update" # (users_controller.rb) def index @users = User.all end def show @user = User.find_by(id: params[:id]) end def new @user = User.new end def create @user = User.new(name: params[:name], email: params[:email]) if @user.save flash[:notice] = "ユーザー登録が完了しました" redirect_to("/users/#{@user.id}") else render("users/new") end end def edit @user = User.find_by(id: params[:id]) end def update @user = User.find_by(id: params[:id]) @user.name = params[:name] @user.email = params[:email] if @user.save flash[:notice] = "ユーザー情報を編集しました" redirect_to("/users/#{@user.id}") else render("users/edit") end end # (layouts/application.html.erb) <header> <div class="header-logo"> <%= link_to("TweetApp", "/") %> </div> <ul class="header-menus"> <li> <%= link_to("TweetAppとは", "/about") %> </li> <li> <%= link_to("投稿一覧", "/posts/index") %> </li> <li> <%= link_to("新規投稿", "/posts/new") %> </li> <li> <%= link_to("ユーザー一覧", "/users/index") %> # 追加 </li> <li> <%= link_to("新規登録", "/signup") %> # 追加 </li> </ul> </header> # (index.html.erb) <% @users.each do |user| %> <%= link_to(user.name, "/users/#{user.id}") %> <% end %> # (show.html.erb) <h2><%= @user.name %></h2> <p><%= @user.email %></p> <%= link_to("編集", "/users/#{@user.id}/edit") %> # (new.html.erb) <% @user.errors.full_messages.each do |message| %> <%= message %> <% end %> <%= form_tag("/users/create") do %> <p>ユーザー名</p> <input name="name" value="<%= @user.name %>"> <p>メールアドレス</p> <input name="email" value="<%= @user.email %>"> <input type="submit" value="新規登録"> <% end %> # (edit.html.erb) <% @user.errors.full_messages.each do |message| %> # エラーメッセージを表示 <div class="form-error"> <%= message %> </div> <% end %> <%= form_tag("/users/#{@user.id}/update") do %> # フォームの送信先を指定 <p>ユーザー名</p> <input name="name" value="<%= @user.name %>"> <p>メールアドレス</p> <input name="email" value="<%= @user.email %>"> <input type="submit" value="保存"> <% end %>
・確認すること
- ヘッダーに「ユーザ一覧」と「新規登録」のリンクが表示されていて、画面遷移できる
- 新規登録画面にて、ユーザの新規登録ができ、適宜エラーメッセージとサクセスメッセージが表示される
- メールアドレスが一意であるなどのバリデーションが有効になっている
- ユーザ一覧ページから各ユーザの詳細ページへ画面遷移できる
- ユーザの詳細ページの編集ボタンより編集ができ、適宜エラーメッセージとサクセスメッセージが表示される
Ruby on Rails5 学習コースⅦ
・テーブルにカラムを追加する
$ rails g migration add_image_name_to_users # マイグレーションファイルのみを作成 # (db/migrate/2018MMDDHHMMSS_add_image_name_to_users) # 作成されたマイグレーションファイルを以下のように編集 def change add_column :users, :image_name, :string # usersテーブルにimage_nameカラムを追加 end $ rails db:migrate # DBに変更を反映
・ユーザ登録時に初期画像を保存
# (users_controller.rb) def create @user = User.new( name: params[:name], email: params[:email], image_name: "default_user.jpg" # ユーザ登録時のimage_nameカラムの値を設定 ) if @user.save : end
・ビューに画像を表示する
# (users/show.html.erb) <img src="<%= "/user_images/#{@user.image_name}" %>">
・画像選択ボタンを表示する
# (users/edit.html.erb) <%= form_tag("...", {multipart: true}) do %> # 画像の送信にはform_tagに{multipart: true}を追加する <h2>画像</h2> <input name="image" type="file"> # 「type="file"」とすることで画像を設定できるようになる
・Rubyのコードでファイルを作成する
$ rails console > File.write("public/sample.txt", "Hello World")
・画像をDBに保存する
# (users_controller.rb) def update : if params[:image] @user.image_name = "#{@user.id}.jpg" # 画像のファイル名をimage_nameカラムに保存 image = params[:image] # 送信されたファイルの情報をimage変数に格納 # image変数の画像データをreadメソッドを用いて取得し、ファイルに書き込む File.binwrite("public/user_images/#{@user.image_name}", image.read) end : end
・完成版
# (db/migrate/2018MMDDHHMMSS_add_image_name_to_users) def change add_column :users, :image_name, :string end # (users_controller.rb) def index @users = User.all end def show @user = User.find_by(id: params[:id]) end def new @user = User.new end def create @user = User.new( name: params[:name], email: params[:email], image_name: "default_user.jpg" # 追加 ) if @user.save flash[:notice] = "ユーザー登録が完了しました" redirect_to("/users/#{@user.id}") else render("users/new") end end def edit @user = User.find_by(id: params[:id]) end def update @user = User.find_by(id: params[:id]) @user.name = params[:name] @user.email = params[:email] if params[:image] # 画像を保存する処理を追加 @user.image_name = "#{@user.id}.jpg" image = params[:image] File.binwrite("public/user_images/#{@user.image_name}", image.read) end if @user.save flash[:notice] = "ユーザー情報を編集しました" redirect_to("/users/#{@user.id}") else render("users/edit") end end # (users/index.html.erb) <% @users.each do |user| %> <div class="users-index-item"> <div class="user-left"> <img src="<%= "/user_images/#{user.image_name}" %>"> # 追加 </div> <div class="user-right"> <%= link_to(user.name, "/users/#{user.id}") %> </div> </div> <% end %> # (users/show.html.erb) <img src="<%= "/user_images/#{@user.image_name}" %>"> # 追加 <h2><%= @user.name %></h2> <p><%= @user.email %></p> <%= link_to("編集", "/users/#{@user.id}/edit") %> # (users/edit.html.erb) <% @user.errors.full_messages.each do |message| %> <div class="form-error"> <%= message %> </div> <% end %> <%= form_tag("/users/#{@user.id}/update", {multipart: true}) do %> # 変更 <p>ユーザー名</p> <input name="name" value="<%= @user.name %>"> <p>画像</p> <input name="image" type="file"> # 追加 <p>メールアドレス</p> <input name="email" value="<%= @user.email %>"> <input type="submit" value="保存"> <% end %>
・確認すること
- 編集画面で画像選択ボタンが表示されていて、画像が保存/表示される
Ruby on Rails5 学習コースⅧ
・ログインページの作成
# (routes.rb) get "login" => "users#login_form" # (users_controller.rb) def login_form end # (users/login_form.html.erb) <p>パスワード</p> <input type="password"> # type="password"を指定して入力内容を伏字にする
・パスワードカラムの追加
$ rails g migration add_password_to_users # マイグレーションファイル作成 # (YYYYMMDDHHMMHH_add_password_to_users.rb) def change add_column :users, :pasword, :string # usersテーブルにpasswordカラムを追加 end $ rails db:migrate # DBに変更を反映
・バリデーションの設定
# (models/user.rb) validates :password, {presence: true}
・ルーティングとアクションの追加
# (routes.rb) post "login" => "users#login" # フォームの値を送信する為postを使用 # (users/login_form.html.erb) <%= form_tag("/login") do %> <p>メールアドレス</p> <input name="email"> <p>パスワード</p> <input type="password" name="password"> <% end %>
・ログイン機能の実装
# (users_controller.rb) def login # ログインするユーザを特定する @user = User.find_by(email: params[:email], password: params[:password]) if @user # ユーザが存在する場合 flash[:notice] = "ログインしました" redirect_to("/posts/index") else # ユーザが存在しない場合 @error_message = "メールアドレスまたはパスワードが間違っています" @email = params[:email] @password = params[:password] render("users/login_form") end end # (users/login_form.html.erb) <% if @error_message %> <%= @error_message %> <% end %> <%= form_tag("/login") do %> <p>メールアドレス</p> <input name="email" value="<%= @email %>"> <p>パスワード</p> <input type="password" name="password" value="<%= @password %>"> <% end %>
・session変数を使用してユーザ情報をブラウザで保持する
# (users_controller.rb) def login @user = User.find_by(email: params[:email], password: params[:password]) if @user session[:user_id] = @user.id : end
・ログアウト機能の実装
# (routes.rb) post "logout" => "users#logout" # sessionの値を変更するのでpostを使用 # (users_controller.rb) def logout session[:user_id] = nil flash[:notice] = "ログアウトしました" redirect_to("/login") end # (layouts/application.html.erb) <% if session[:user_id] %> <li> <%= session[:user_id] %> </li> :
・ユーザ登録時のログイン
# (new.html.erb) : # パスワード用のフォームを追加 <p>パスワード</p> <input name="password" type="password" value="<%= @user.password %>"> : # (users_controller.rb) def create @user = User.new( name: params[:name], email: params[:email], image_name: "default_user.jpg", password: params[:password] # passwordカラムの値を設定 ) end
・ユーザ登録時にログイン状態にする
# (users_controller.rb) def create @user = User.new(...) if @user.save session[:user_id] = @user.id # 新規登録時にログイン状態にする :
・ユーザ名の表示
# (layouts/appilcation.html.erb) <% current_user = User.find_by(id: session[:user_id]) %> <li> <%= link_to(current_user.name, "/users/#{current_user.id}") %> </li>
・アクション側で共通の変数を定義する
# (application_controller.rb) before_action :set_current_user # 全てのコントローラーで共通する処理は纏める def set_current_user @current_user = User.find_by(id: session[:user_id]) end
・アクセス制限の処理を共通化する
# (application_controller.rb) def authenticate_user if @current_user == nil flash[:notice] = "ログインが必要です" redirect_to("/login") end end # (users_controller.rb) # onlyを用いて適用したいアクションを指定 before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
・ログインユーザがアクセスできないページの設定
# (application_controller.rb) def forbid_login_user if @current_user flash[:notice] = "すでにログインしています" redirect_to("/posts/index") end end # (home_controller.rb) before_action :forbid_login_user, {only: [:top]} # (users_controller.rb) before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}
・ユーザの編集を制限する
# (users/show.html.erb) # 詳細ページのユーザidとログインユーザidが等しい場合のみ編集ボタンを表示 <% if @user.id == @current_user.id %> <%= link_to("編集", "/users/#{@user.id}/edit") %> <% end %> # (users_controller.rb) before_action :ensure_correct_user, {only: [:edit, :update]} def ensure_correct_user # 正しいユーザかどうかを判定する if @current_user.id != params[:id].to_i # to_iメソッドで文字列を数値に変換 flash[:notice] = "権限がありません" redirect_to("/posts/index") end end
・完成版
# (routes.rb) get "login" => "users#login_form" # 追加 post "login" => "users#login" # 追加 post "logout" => "users#logout" # 追加 post "users/:id/update" => "users#update" get "users/:id/edit" => "users#edit" post "users/create" => "users#create" get "signup" => "users#new" get "users/index" => "users#index" get "users/:id" => "users#show" get "posts/index" => "posts#index" get "posts/new" => "posts#new" get "posts/:id" => "posts#show" post "posts/create" => "posts#create" get "posts/:id/edit" => "posts#edit" post "posts/:id/update" => "posts#update" post "posts/:id/destroy" => "posts#destroy" get "/" => "home#top" get "about" => "home#about" # (application_controller.rb) before_action :set_current_user def set_current_user @current_user = User.find_by(id: session[:user_id]) end def authenticate_user if @current_user == nil flash[:notice] = "ログインが必要です" redirect_to("/login") end end def forbid_login_user if @current_user flash[:notice] = "すでにログインしています" redirect_to("/posts/index") end end # (home_controller.rb) before_action :forbid_login_user, {only: [:top]} # 追加 def top end def about end # (posts_controller.rb) before_action :authenticate_user # 追加 def index @posts = Post.all.order(created_at: :desc) end def show @post = Post.find_by(id: params[:id]) end def new @post = Post.new end def create @post = Post.new(content: params[:content]) if @post.save flash[:notice] = "投稿を作成しました" redirect_to("/posts/index") else render("posts/new") end end def edit @post = Post.find_by(id: params[:id]) end def update @post = Post.find_by(id: params[:id]) @post.content = params[:content] if @post.save flash[:notice] = "投稿を編集しました" redirect_to("/posts/index") else render("posts/edit") end end def destroy @post = Post.find_by(id: params[:id]) @post.destroy flash[:notice] = "投稿を削除しました" redirect_to("/posts/index") end # (users_controller.rb) before_action :authenticate_user, {only: [:index, :show, :edit, :update]} # 追加 before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]} # 追加 before_action :ensure_correct_user, {only: [:edit, :update]} # 追加 def index @users = User.all end def show @user = User.find_by(id: params[:id]) end def new @user = User.new end def create @user = User.new( name: params[:name], email: params[:email], image_name: "default_user.jpg", password: params[:password] # 追加 ) if @user.save session[:user_id] = @user.id flash[:notice] = "ユーザー登録が完了しました" redirect_to("/users/#{@user.id}") else render("users/new") end end def edit @user = User.find_by(id: params[:id]) end def update @user = User.find_by(id: params[:id]) @user.name = params[:name] @user.email = params[:email] if params[:image] @user.image_name = "#{@user.id}.jpg" image = params[:image] File.binwrite("public/user_images/#{@user.image_name}", image.read) end if @user.save flash[:notice] = "ユーザー情報を編集しました" redirect_to("/users/#{@user.id}") else render("users/edit") end end def login_form end def login @user = User.find_by(email: params[:email], password: params[:password]) if @user session[:user_id] = @user.id flash[:notice] = "ログインしました" redirect_to("/posts/index") else @error_message = "メールアドレスまたはパスワードが間違っています" @email = params[:email] @password = params[:password] render("users/login_form") end end def logout session[:user_id] = nil flash[:notice] = "ログアウトしました" redirect_to("/login") end def ensure_correct_user # 追加 if @current_user.id != params[:id].to_i flash[:notice] = "権限がありません" redirect_to("/posts/index") end end # (layouts/application.html.erb) <header> <div class="header-logo"> <% if @current_user %> <%= link_to("TweetApp", "/posts/index") %> <% else %> <%= link_to("TweetApp", "/") %> <% end %> </div> <ul class="header-menus"> <% if @current_user %> <li><%= link_to(@current_user.name, "/users/#{@current_user.id}") %></li> <li><%= link_to("投稿一覧", "/posts/index") %></li> <li><%= link_to("新規投稿", "/posts/new") %></li> <li><%= link_to("ユーザー一覧", "/users/index") %></li> <li><%= link_to("ログアウト", "/logout", {method: :post}) %></li> # postを指定 <% else %> <li><%= link_to("TweetAppとは", "/about") %></li> <li><%= link_to("新規登録", "/signup") %></li> <li><%= link_to("ログイン", "/login") %></li> <% end %> </ul> </header> # (users/show.html.erb) <h2><%= @user.name %></h2> <p><%= @user.email %></p> <% if @user.id == @current_user.id %> # 追加 <%= link_to("編集", "/users/#{@user.id}/edit") %> <% end %> # (/users/login_form.html.erb) <% if @error_message %> <div class="form-error"> <%= @error_message %> </div> <% end %> <%= form_tag("/login") do %> <p>メールアドレス</p> <input name="email" value="<%= @email %>"> <p>パスワード</p> <input type="password" name="password" value="<%= @password %>"> <input type="submit" value="ログイン"> <% end %> # (/users/new.html.erb) <%= form_tag("/users/create") do %> <p>ユーザー名</p> <input name="name" value="<%= @user.name %>"> <p>メールアドレス</p> <input name="email" value="<%= @user.email %>"> <p>パスワード</p> <input type="password" name="password" value="<%= @user.password %>"> <input type="submit" value="新規登録"> <% end %>
・確認すること
- ログイン前のヘッダーのリンクは、「TweetApp」「TweetAppとは」「新規登録」「ログイン」
- 「TweetApp」は、トップページへ画面遷移する
- 「ログイン」より、ログインページへ画面遷移し、ログインできる(パスワードは伏字)
- ログイン時、エラーメッセージ又はサクセスメッセージが表示される
- ログイン後のヘッダーのリンクは、「TweetApp」「ログインユーザ名」「投稿一覧」「新規投稿」「ユーザ一覧」「ログアウト」
- 「TweetApp」は、投稿一覧ページへ画面遷移する
- 「ログインユーザ名」は、ユーザ詳細ページへ画面遷移する
- 「ログアウト」より、ログアウトできる
- ログイン前のアクセスが制限できている
- ログインユーザがアクセスできないページが設定できている
- 他ユーザの編集ができないよう制限できている
[siteorigin_widget class=”AdWidgetItem”][/siteorigin_widget]
[siteorigin_widget class=”WP_Widget_Search”][/siteorigin_widget]
[siteorigin_widget class=”WP_Widget_Pages”][/siteorigin_widget]
[siteorigin_widget class=”AdWidgetItem”][/siteorigin_widget]