Railsの学習(5日目)
はい
今回の目標
まずはユーザーのデータを保存できるようにユーザーテーブルとユーザーモデルを作っていく。
そのためにrails consoleで「rails g model User name:string amail:string」と打ち込めば作成できる。stringというのは短文という意味で、Userというモデル名にnameとemailというカラムに短い文字列データがそれぞれ入りますよ、というイメージ
rails consoleでユーザーデータを保存してみる
user = User.new()で名前とメールアドレスを入力して、保存。idと作成日は自動的に保存される。
バリデーションを追加し、名前とメールアドレスが空でも登録できないようにする。
以下の図のように「validates :email,{uniqueness: true}」(唯一の、独自の)を指定することでチェックすることができる。前にやった投稿内容のときはpresence:trueだったな。一つのvalidatesで複数の内容を指定できるので、空のカラムと重複したカラムを弾くには「validates:email,{uniqueness: true, presence: true}」とすれば良い。
ユーザー一覧ページを作る。
そのためにuserコントローラとuserアクションを作り、データベースからデータを取得して全ユーザーが表示されるようにする。
ユーザー詳細ページのURLには「localhost:3000/users/1」のように、ユーザーデータのidを含めるようにする。また、下の図のように、ユーザー一覧ページのユーザー名から詳細ページに飛べるようにリンクに設定する。
ユーザーの新規登録〜ユーザーデータの保存〜
フォームに送信された値を送信するために、名前とメールアドレスそれぞれにname属性を指定する。name属性の名前がハッシュ呼び出しのキーになるため、分かりやすいネーミングをすること。
新規登録に失敗したときにエラーメッセージと前回の内容を維持したまま表示できるようにする。
<input>タグでは、value属性の値が初期値にな流ため。value属性に値を指定すると右の図のようにフォームに初めから値が入力された状態で表示できる。
inputの中の初期値をRubyのコードから引っ張ってくるには<%=%>と@と""を用いてvalueに代入する。
アカウント編集ページではユーザーが登録したデータを初期値にしたい。そのため、ユーザー編集ページのURLには「localhost:3000/users/1/edit」のように、編集するユーザーのidを含め、ユーザー編集フォームには初期値を設定しておく。
また、左の画像のようにユーザー詳細ページに編集ページへのリンクを用意しよう。
データベースにファイル名を保存するカラムを作成する。
データベースを変更していくにはマイグレーションファイルを作成し、それをデータベースに反映させていく。ちなみに今回はマイグレーションファイルだけでいいので
rails consoleでは「rails g model migration」ではなく「rails g migration」で出力する。
ファイル名は自由に決められるが、先頭に日付が追加される。分かりやすい名前が良い。
今回作成されたマイグレーションファイルにはテーブルに変更を加えるための命令が書いてないので、以下のようにchangeメソッドに書く必要がある。
rails modelによって生成されてきたマイグレーションファイルにはchangeの中身が自動生成されていたため、特に変更なく使うことができていた。
そこで今回は自分で書く必要がある。その場合、左の画像のように「add_colum :テーブル名, カラム名 , データ型」というコードを書く。書いたら右のようにrails db:migrateでデータベースに変更を反映する。これによりユーザーデータにimage_nameカラムが追加される。
初期画像(twitterでいう卵みたいなアレ)を用意する。
初期画像のファイル名がdefault_user.jpgなので、ユーザー登録時に、image_nameカラムの値が「default_user.jpg」になるようにする。そうすることで自動的に初期画像が反映される。createアクション内の@userアクション内でnewメソッドの引数としてimage_nameを指定すれば命令として成立する。
画像を表示するには今まで通りHTMLで表示する必要がある。これはディレクトリの概念そのもので、public/user_imagesフォルダに画像が入っているため、/user_images/ファイル名とすれば表示されるようになる。もちろん@userのようなrubyのコードを引っ張ってきているので、<%=%>で囲う必要がある。
ユーザー毎に画像選択できるようにする。
そうするためにはinputタグに「type="file"」を書くことで画像の選択が可能になる。また、name属性をimageにしておく。
画像の送信は特殊なので、form_tagに「{multipart: true}」をつける必要あり。
画像のアップロード
そのために、右図のようにupdateアクションでファイル名をデータベース保存し、画像ファイルをpublicフォルダに保存していく。
Rubyのコードで画像を扱うにはあらかじめ用意されている、fileクラスを用いる。
ファイルを作成するにはfileクラスのwriteメソッドを使う。つまり、左図のように「file.write("ファイルの場所,ファイルの中身")」とする。file.writeの場所はpublicを指定する。これによってHello Worldと書かれたテキストファイルが完成する。
画像の保存
流れはさっきと同じ。updateアクションでデータベースにファイル名を保存し、画像をpublicフォルダに保存する。
まずはnameやemailを更新した時と同じように、updateアクション内で@user.image_nameの値を上書きする。そして画像の名前をユーザーのid名として保存されるように、#{@user.id}.jpgとする。
画像ファルもnameやemailと同様にparams[:image]として受け取ることができる。この中には送信された画像の情報が入っているので、これを利用してpublicフォルダに保存されるようにしていく。
画像を保存するためには画像データを下に画像ファイルを作る必要がある。ファイルを作るにはFileクラスを使用するが、前回使ったFile.write ではなく、File.binwriteをつかあって保存する。これはコンピュータが画像をbinaryで認識しているからだと思われる。図のように変数imageに対してreadメソッドを用いることで画像を読み込むことができる。
画像が保存されるのは画像が送信された時のみにするために、if文を用いて実行する(endを忘れないように!)。
ログインについて
ログインとは、サイトを操作しているユーザーが誰かを特定できる状態のこと。ログインすることにより、同じURLでもその人に合わせた表示をしたりできる。
ログインするためにはメールアドレスとパスワードをrailsに送ってデータベースと称号し、特定する必要がある。
ログインを作るときも、まずはrooting, action,viewを追加する。
今回は「localhost:3000/login」でlogin_formアクションを呼び出せるようにする。
作成したlogin_form.html.erbに<input tyoe="password">として属性をpasswordにすると、パスワードフォームで伏せ字表示ができる。
パスワードカラムの追加
rails consoleで「rails g migration add_password_to_users」と入力し、マイグレーションを変更する。そして新しく作られたmigrateファイルにchangeクラスを作り、その中に「add_column :テーブル名, :カラム名, :データ型」を書く。そして「rails db:migrate」を実行すると、データベースにpasswordカラムが追加されている。
passwordにも必ず値が欲しいので、validationで有無の判定をしたい。その際はpresence:trueで良い。
フォームの値を送信できるようにする。
フォームから送信された値を受け取るためにrootingとactionを追加する。フォームの値を送信するため、postを使うことに注意。
form_tagメソッドを用いてlogin_form.html.erbにURLの送信先を指定(/login)する。
また入力された値がrails側に送信されるようにメールとパスワードの<input>タグにname属性をつけること。
/loginで一見二つのrootingがかぶってるように見えるが、getとpostで別のrootingなので問題はない。(link_toメソッドではデフォルトでgetのルーティングを探し、form_tagメソッドがデフォルトでpostのルーティングを探すようになっている。)
ログイン機能の流れ
ログインするユーザーを特定するにはフォームから入力された値をデータベースから参照し、一致するユーザーがいたらそのデータを主録し、@userに代入する
一致したユーザーがいた場合、フラッシュメッセージを表示するようにしてUserの投稿画面にリダイレクトし、いなかった場合は再度ログインフォーム入力画面にリダイレクトしてを表示するようにしているのが左の画像。