Progate道場コースRuby on Rails5 Ⅲまで完遂したので、その時点の知識でRailsでサービスを作っていく流れをまとめてみる

Progate道場コースRuby on Rails5 Ⅲまで完遂したので、その時点の知識でRailsでサービスを作っていく流れをまとめてみる

※自分用メモのため、情報はかなり飛び飛び

ざっくりした流れ

・ターミナルにて以下のコマンドでプロジェクトを作成。色々なファイルが生まれる。

アプリ新規作成後は、githubと連携しておくと、ファイル管理がしやすくなる。

連携については、下記の記事を参照。

※vscodeを使用して上記の手順を試みたところ、git pushの際に下記のエラーが発生した。

正しいアクセス権があるか、または、リポジトリが存在することを確認してくださいとのこと。

「git remote -v」を実行してみて、以下のように自身のリポジトリが表示された場合には、リポジトリは存在はあるので、アクセス権がないっぽい。

その場合は、下記の記事の手順を参照して改善できた。

※上記記事の「ssh-keygen -t rsa -C mail@mail.com」を実行時に以下のメッセージが表示されたが、これはデフォルトのターミナル(Command Prompt)でsshのコマンドが使用できないためらしい。

Git Bashではsshのコマンドが使用できるため、vscodeのターミナルをbashに切り替えて実行すると、「ssh-keygen -t rsa -C mail@mail.com」を実行できた。

アプリ作成後

・コントローラーを作成(機能ごとにコントローラーを作成するのが良いらしいが機能ごとってどんなもんよ?異なるデータベースを操作、参照する場合に別コントローラーにした方が良いって感じかな…)

・ルーティンはリンクみたいなもの(?)で、そのルーティンにアクセスした際に、ルーティンで設定したコントローラー内のアクションに接続することで、アクションを実行できる

・アクションは、controllerファイル内で定義

・アクション内には、redirect_toやrender等、何かしらページを描画する操作が必要で、これが無いとNoテンプレートエラーになっちゃう。ただし、一つのアクション内でredirect_toやrenderが同時に行われる操作が実行されると、これはこれでエラー(ダブルテンプレートエラー)になっちゃうので注意。同時に描画されないように条件分岐などを行いましょう。

※アクションを何も設定していない場合、view内のアクション名のページをrenderするという操作が行われるらしい。

・トップページへのルーティンについては、以下で可能

各データベースについて

・投稿された内容や、各ユーザーのデータ等のデータベースを管理するための「モデル」は下記で作成(単数形で指定するのに複数形の名前のテーブルができるよ。不思議)

その後、以下のコマンドでデータベースへ反映させることにより、テーブルが作成される。

・後からテーブルにカラムを追加したい場合、

でmigrationファイルを作成後、ファイル内で以下の記載。

その後、ターミナルでrails db:migrate実行により、テーブルにカラムを反映させることができる。

カラムを削除したい場合には、rails g migration ファイル名で再度migrationファイルを作成した後、作成したファイル内に、以下のように「remove_column」を記載し、rails db:migrateを実行する。

 

※作成したテーブルの中身を確認したい場合は、下記参照

https://qiita.com/Kohei_Kishimoto0214/items/6e9611ac7680d1dfcf15

※作成したテーブルの一覧や構造を確認したい場合は下記参照

https://qiita.com/kouuuki/items/b6e1a4318d8feee24c9f

○○の一覧を表示させる場合

いわゆる、ツイッターの投稿一覧が表示されているような箇所。

全ての情報が表示されるので、@posts=Post.allのように、テーブルのすべての情報を格納したものを、Viewで表示させていく。

特定の条件で絞り込んだ情報を表示させる際には、コントローラー側で@posts=Post.where(user_id:3)のようにwhereメソッドを使用すると良さそう。

whereメソッドはfind_byと似た感じで、テーブルのデータを探すメソッドだが、find_byの場合は、探したデータのうち一つしかデータを取得することが出来ない。

whereの場合は、該当するデータすべてを引っ張って来るので、TPOに併せて使う。

Viewで表示させる際には、each文を利用して、テーブルに格納されているデータをそれぞれ表示させたい場所に、ぶっこんでいく。

 

フラッシュメッセージについて

ユーザーが何らかの操作を行った際に簡易的なメッセージを使用したい場合(ログインしました、パスワードが違います等)に、flashという変数を使用する。

flashは、次のリクエストが送信されるまで、代入した値を保持し続ける感じの変数なので、以下のように、アクション内でflashメッセージを定義し、Viewで表示することで、1回分のリクエストを受けた時のみ表示できるメッセージ機能を実装できる。([:notice]の部分は任意に名前を設定可能)

flash[:notice]=”ログインしました”

Viewでは、以下のように、flashメッセージがあるかどうかでメッセージの表示を分岐させるとよい。

あと、フラッシュメッセージのシンボル([:notice]の部分)を統一して、application.html.erb(全てのページで表示されるHTMLを記載するファイル)に上記を格納しておくと、アクションごとにフラッシュメッセージを代入するだけで、異なるフラッシュメッセージを表示できるので便利。

ログイン機能について

「ログイン」機能というものが明確にある訳ではない。

「session」という、ブラウザにアクセスしている期間中ずっと使いまわせる特別の変数を用いることにより、ログインしている状態っぽい環境を作り出す。

例えば、ログイン時のアクションを以下のような流れにすることで、ログインしているっぽい環境を生み出すことが出来る。

・@user = User.find_by(email: params[:email],password: params[:password])で、メルアドとパスワードが一致したユーザーを探し出して、@userに代入する。※paramsは、ログインページのフォーム内で、inputやtext要素のname属性に指定した値の箇所に入力した内容を受け取ることが出来る。

・session[:id] =@user.idで、ログインしたユーザーのidを代入する(idはデータベースがcreateされる度に個別に作られるため同一になることは無い。)

・session[:id] の値と、アクセスしたURLのparams[:id]が一致しているかどうかで、ユーザー情報の編集ができるかどうかを条件分岐させる。(「編集」ボタンを表示させないようにするとか、そもそもURLにアクセスできないようにするとか、色々方法はある)

※例えば、【「編集」ボタンを表示させないだけ】を実装すると、ログインしていないユーザーでも、直接URLで編集画面にアクセスすることでデータの編集ができてしまうため注意

・User.find_by()で、値が何も見つからない場合session[:user_id]=nilになるので、ログインしていない状態はsession[:id]=nilで認識できる。また、ログアウト操作の場合にはsession[:id]=nilをアクションに含めればOK。

・さらに、ApplicationControllerで以下のアクションを指定しbefore_actionで実行すると、他のコントローラーでも現在ログイン中のユーザー、つまり@current_userを使用できるから、便利だよ。

before_actionをコントローラー内に記載すると、各コントローラーの各アクション前に実行される。ApplicationControllerのアクションは継承によりその他のアクションでも実行できるので、ApplicationControllerでbefore_actionを指定した場合、実質すべてのアクション前に実行される…と思われる…。

フォームからデータを受け取る際

ユーザーの新規作成など、HTML側で情報を入力して受け取る際の操作では、以下のようにform_tag(“リクエストの送信先”)do ~ endを使用する

form_tag(“/users/create”) do

●●●

end

input要素(またはtextarea要素)のname属性で指定した値は、ルーティン先のコントローラー内で、params[:name属性で指定した値]で受け取ることができる。

ログインフォームなどは、User.find_by(email: params[:email], password:params[:password])のように、フォームで入力した情報と一致したかどうかで、該当ユーザーログイン操作の条件分岐を行う。

入力内容に制限を設ける

ユーザー名やパスワードが、空白で作成されないよう制限を設ける場合には、validationsを使用する

validationsはmodelsフォルダの該当テーブルのファイルにvalidatesを記載することで設定できる。
※以下では、emailカラム、passwordカラムに空白を制限(presence: true)、emailカラムに同一のアドレスを防ぐ(uniqueness: true)バリデーションを実装している

また、上記の条件を満たしていないデータの入力に対してエラーメッセージを表示させる場合には、controllerでエラーメッセージを取得後、Viewで取得したエラーメッセージのeach文で回すことで、取得した全てのエラーメッセージを表示させることができる(Viewでは、if文で条件分岐させないとNoMethodErrorになるため注意)

※View側

いいね機能

いいね機能では「だれがいいねしているか」と「どの投稿をいいねしているか」の2つの情報が必要。

その2つのカラムを持ったLikesテーブルを作成することで実装する。

テーブル作成後は、以下のように、Postモデルの中に投稿者のUserデータを返すインスタンスメソッドを指定しておくと、該当の投稿と、投稿者データを紐づけやすくできる。

インスタンスメソッドを使用する際には、@post.user指定。

その後、@post.user.nameなど、Userクラスの値を指定することで、投稿者のUserクラスのデータを引っ張り出すことができる。

パスワード機能

パスワードについては、Rails内にbcryptというGemをインストールして使う。(Gemは、Railsに機能を追加できるプラグインみたいなものかな…?)

素人があれこれ考えるより、既に使われている物を使った方が絶対に良いので上記を使っていく。

Gemのインストールは、gemfileに以下の内容を記載後、ターミナルでbundle installを実行でインストールできる。

ちなみに、Gemfileの仕組みは以下のようになっているらしい。

GemfileとはRailsアプリで利用するgemが記述されているファイルのことです。

Gemfileを参照することで、Railsアプリを動作させるためにはどのgemをインストールすればいいのかがわかります。

gemをインストールするときはbundle installというコマンドを実行するのですが、このときbundlerがGemfileを参照し、Gemfileに記述されているgemの中でインストールされていないものを見つけてインストールを実行します。

【初心者向け】GemfileとGemfile.lockの違い

bcryptをインストール後は、 has_secure_passwordメソッドと、authenticateメソッドが使えるようになる。

※インストール後、上記メソッドを使用する際に「cannot load such file — bcrypt」と表示される場合には、rails serverの再起動で治る

has_secure_password

→passwordカラムに保存したパスワードを、暗号化して、password_digestカラムに保存する。

使い方は、has_secure_passwordメソッドを使用したいモデルに「has_secure_password」を記載するだけ。

userモデルに使用したい場合は、以下のように記載。

has_secure_passwordメソッドを使用すると、passwordカラムではなく、password_digestカラムに暗号化したpassを保存するようになる。
そのため、password_digestカラムの追加と、passwordカラムの削除(作っていた場合)が必要になる。
なお、has_secure_passwordメソッドを使用した場合、passwordをpassword_digestに変更してくれる機能もある。
(テーブルにpasswordカラムが無くても以下の記載でpassword_digestに保存される。)

authenticate

→password_digestの値と、authenticate(引数)の値が一致しているかを調べるメソッド。
※@user.authenticate(params[:password])==@user.password_digestという使い方ではないため注意。
ログインのアクション時には以下のように記載することで、そのユーザーが存在するか(最初の条件の「@user」)、および、password_digestの値とフォームで入力したパスワードが一致しているか(2つ目の条件の「@user.authenticate(params[:password])」)で条件分岐させる。

その他注意点や詰まったところ

・link_toでpostリクエストに送信する際には、以下のように {method: “post”}を引数に加える。

・Railsというよりは、Ruby自体の問題だが、シンボルの使いどころが良くわからん。。。

とりあえず、before_actionでメソッドを指定する場合には、以下のようにシンボルで指定する。あと、Onlyの中身は配列形式にする必要があるよ。

・画像のアップロード操作を行う際には以下の操作を行う。流れを覚えるのが難しいのでとりあえず暗記。

①form_tag内のリクエスト送信先とあわせて、以下のように「{multipart: true}」を指定する。

②フォーム内の画像ファイルをアップロードしてもらうinput要素に「type=”file”」を指定。

③params[:image]がある場合には以下の操作を実行

@user.image_nameには、”#{@user.id}.jpg”を代入することにより、ユーザー毎に重複しない画像ファイル名を代入している。

※投稿毎の画像ファイルを作成したい場合には、多分@post.idで指定すればいいのかな?

File.binwriteは、Rubyによる、画像ファイルを作成する際の特別の操作。引数には、(“ファイルパス” , params[:image].read)を指定。

④最後に画像を表示させたい箇所に以下を記載。(publicに保存しているファイルでも、何故かファイルパスをpublicから始めると読み込まない…)