AFTER CODEBSE School 4week

今週はProgate Railsを22時間やって、やっとProgate Rails 1周完了した(Progate Railsにかけた時間合計で37時間ぐらい)

f:id:shimabukuromeg:20180416202814p:plain

まとめ

  • とりあえず1週したけどすぐ忘れそうなのでいい感じに復習するようにする
  • CODE BASEのプログラミング講座終わって1ヶ月がたった。
  • ざっくりだけど週20時間ペースの学習時間
  • この1ヶ月でやったこと

    • ドットインストール(slim、ActiveRecord
    • Progate (rubyrails
    • ruby環境構築
    • たのしいrubyを読む(8章の途中までクラスとモジュールのやつ)
    • 卒業制作のslimアプリ制作の続き(一旦ストップ)
  • 次の1ヶ月で終わっていたいこと

以下、progate rails 作業メモ

Progate Rails まとめメモ

Progate Rails 1

アプリケーションの作成

    $ rails new アプリケーション名

サーバー立ち上げ

    $ rails server

トップページ作成

    $ rails generate controller home top

※home・・・・コントローラー名

※top・・・・・アクション名

※新しくページを作る時に、一度作ったコントローラー名と同じコントローラー名で、このコマンドを利用して、ページを作ることはできない(コントローラーのファイルがすでに作られてるから)

ページ作成に必要な3要素

  • ビュー
    • ビューとは、ページの「見た目」を作るためのHTMLファイルです。
    • app/views/home/top.html.erb が作られる
    • 「erb」とは「Embedded Ruby(埋め込みRuby)」の略
    • 埋め込むRubyコードをブラウザに表示したい場合は、<% %>ではなく、<%= %>を用います。
    • CSSファイルの場所は、app/assets/stylesheet/home.scss 例のコマンド(rails generate controller home)叩いた時に作られる。
    • 画像とかは、publicフォルダへ保管する
  • コントローラー
    • ページを表示するとき、Railsの中ではコントローラを経由してビューをブラウザに返しています。
    • app/controller/home_controller.rb
    • コントローラー内のメソッドをアクションという
    • コントローラ内のアクションは、ブラウザに返すビューをviewsフォルダの中から見つけ出す役割を担っている
    • アクションは、コントローラと同じ名前のビューフォルダから、アクションと同じ名前のHTMLファイルを探してブラウザに返します。
    • コントローラーは目的に合わせて作成する
      • トップページに関するコントローラ
      • 投稿に関するコントローラー(投稿一覧/新規投稿など)
  • ルーティング
    • Rails内ではコントローラを経由してビューを返していますが、ブラウザとコントローラを繋ぐ役割を担うのがルーティング
    • ページが表示されるまでの流れは、ルーティング→コントローラ→ビュー
    • ルーティングは、送信されたURLに対して「どのコントローラの、どのアクション」で処理するかを決める対応表のことです。
    • ブラウザでURLを入力すると、ルーティングがURLを見て、適切なコントローラのアクションを呼び出します。
    • get "URL" => "コントローラー名#アクション名"

Routesって何ですか?

  • URLとHTTPメソッドに応じて適切なコントローラにリクエストを振り分けるのがroutes

コントローラーって何ですか?

  • 受け付けたリクエストを処理するのがコントローラー

ビューって何ですか?

  • コントローラでの処理の結果を受け取って、HTMLを返すのがビュー

Progate Rails 1 まとめ

  • まず、Routes,コントローラー,ビューの概念を理解するための説明など。
  • そのあと、routesを変えたり、cssを適用したり、手を動かしながら上記概念を理解する
  • 全体的にtopページ、aboutページを作ってみるのに必要な知識把握できる

Progate Rails 2

  • Progate Rails 1 は、homeコントローラーの話だったけど、Progate Rails 2 は、Postコントローラーの話っぽい。Post コントローラー を使って、投稿に関するリクエストを処理する

Post(投稿)ページ作成

 $ rails generate controller posts index

※posts・・・・コントローラー名 ※index・・・・・アクション名。(一覧ページを作成する時は、indexというアクション名を使用することが一般的)

  • 投稿一覧ページのhtml(ビュー)作った
  • 投稿一覧ページの内容を変数を使って表示できるようにした
  • 投稿が徐々に増えていくことを想定して、投稿内容は配列にまとめるようにした
  • ここまで、上記内容は、全部ビューに書いてたけど、ほんとはアクション(コントローラー)に記述するのが一般的なので、アクションに記述し直した。アクションで定義した変数をビューで使いたい場合は、アクションで定義する変数に@(アットマーク)をつける。そうすれば使える。
  • データベース(テーブル)を用意して、データベースに格納しているデータを取ってきて、投稿一覧ページを表示できるようするために

    マイグレーションとは?

  • データベースに変更を加えること。
  • データベースに変更を加えるためのファイルを生成するコマンド
    $ rails g model Post content:text

※ Post・・・テーブル名の単数形 ※ content・・・カラム名 ※ text・・・データ型

  • 上記コマンドを実行すると、db/migrateフォルダの下にマイグレーションファイルが作られる
  • 上記コマンド実行で作成されたマイグレーションファイルをデータベースに反映させるコマンド $ rails db:migrate

マイグレーションファイルが存在していてい、そのマイグレーションファイルがDBに反映されていない状態だと、Railsではエラーになる。なので、マイグレーションファイルを作成した後は、必ず、rails db:migrateを実行しましょう

モデルとは、テーブルを操作するためのクラス

  • rails g model Post content:text を実行した際に、以下2つのファイルが作られる
    • app/modelsフォルダにモデルが定義されたファイル
    • db/migrateフォルダにマイグレーションファイル
  • ApplicationRecordを継承したクラスをモデルという
    • ApplicationRecordクラスとは????
  • モデル(クラス)から、インスタンスを作成(Post.new)して、そのインスタンスを使って、テーブルのデータを操作する
  • インスタンスを作成した後、データを保存するには、saveメソッドを使う。
  • 登録したデータを取得するときは、Post.firstを使う
  • 登録したデータを全て取得するときは、Post.allを使う。配列で取得できる

    rails consoleとは?

  • Ruby のコードを手軽に実行できるやつ

共通のレイアウトをまとめる方法

  • Railsでは、views/layouts/application.html.erb にヘッダーなど共通部分を書いてあげれる
  • 共通レイアウト views/layouts/application.html.erb に記述されてる <%= yield %> の部分に、他のビューファイルが代入される感じになる

Progate Rails 2 まとめ

  • モデル、マイグレーションの概念理解。Railsマイグレーションファイル作成、反映するの場合のコマンド説明など
  • rails consoleで、モデルのインスタンスで、テーブルへの操作するのを理解できるよう手を動かす感じ。
  • 最終的には、テーブルからデータを取得し、投稿ページが表示できるようになった。
  • この時点では、テーブルのデータを取ってきて、表示させてるだけで、テーブルにデータを登録するなどはできていないので、Progate Rails 3でデータの更新などはやっていく流れっぽい。

Progate Rails 3

  • 前回(Progate Rails 2)が投稿ページを表示するというような内容で、Progate Rails 3は実際に投稿 = データ保存する方法をお勉強するっぽい。
  • テーブルから特定のidの投稿(レコード)を取得するためには、find_byメソッドを利用する。例えば、Post.find_by(id:2) で、idが2のレコードを取れる。前回までは、Post.firstとかだったやつのid指定パターン
  • 投稿したコメントの詳細ページを表示できるようにした。詳細ページは、投稿コメントのidをURLに含めるようにして、そのidの値をparams[:id]で取得するような感じ。
  • 【復習】routesは、リクエスト(メソッドとパス)とコントローラー(アクション)を結ぶ定義が書いていあるファイル
  • 【復習】コントローラーのファイルは、受け付けたリクエストを処理する、コントローラーと同じ名前のビューのディレクトリからアクションと同じ名前のビューファイルを探して、ブラウザに返す
  • 投稿一覧ページの各投稿をlink_to(表示内容,”リンク先パス”)メソッドを使って、詳細ページへリンクするようにした
  • 新規投稿ページを作成した。ざっくり、新しくページを追加したい場合の流れは以下。
    • routesに新しいページへのリクエストとコントローラー(アクション)を追加する
    • コントローラに、いったんアクションだけ記述する。def アクション end って感じ。
    • 表示させるビューファイルを作成する。
    • これで、新しく追加予定のリクエストにアクセスしてみて、ビューファイルの内容が表示されることを確認すればOK。
  • 入力ファオームを作成した。新しく作ったページにform定義を書いた。入力フォームには、form_tagメソッドを使った。 form_tag(送信先のURL) do end
  • フォームからPostした際の処理(routes,コントローラー)を追加した。
  • 更に、createアクションの中身を追加した。
  • アクションでの処理は、基本的にアクションと同じ名前のビューファイルを探して、表示させるような動きになるはずだけど、アクションでの処理の中身にリダイレクトの処理などが書いてたら、必ずしもそうなるわけじゃない。redirect_to()メソッド
  • フォームのinput要素のname属性を設定すると、name属性の値をキー、入力された値をバリューとしたハッシュが、Rails側へ送信できる。(Rails側のコントローラーのアクションで受け取れる。params[:キー] って感じ)
  • 投稿一覧のメッセージをorderメソッドを使って並び替えした。Post.all.order(created_at: :desc)

Paramsとは

  • paramsとは、Railsで送られてきた値を受け取るためのメソッドです。
  • 送られてくる情報(リクエストパラメータ)は主に、以下2通り。(侍エンジニア塾説明)
    • getのクエリパラメータ
    • Postでformを使って送信されるデータの2つです。
  • paramsは以下の2通りの使い方があるので、整理して覚えておきましょう。(Progate説明)
    • 「:○○」を使ったルーティングのURLから値を取得する
      • get “/post/:○○ => “”
    • 「name="○○"」が付いたフォームの入力内容を受け取る

Progate Rails 3 まとめ

  • フォームからデータを登録する方法を勉強した
  • 特定のidのデータを取得する方法 find_by()

Progate Rails 4

  • proate rails 3 でフォームに入力したデータをDBに保存するやり方を学んで、今回はそのデータを更新/削除する処理のお勉強をする感じっぽい
  • rails consoleを使って、削除と編集(update)の処理を手を動かして理解する。find_by()メソッドを使う。
  • rails console でpost.destroyとかpost.content = “変更値” post.saveとかで、データの操作を理解したら、今度はそれをビューのフォームとかからできるようにする
  • 【復習】新しいページを作るとき

    • routesにルート追加
    • コントローラーにアクション追加
    • ブラウザに返すビューを追加
  • link_toメソッドを使って、post用のリンクを作る(削除したい場合) link_to("表示内容","パス",{method: "post"})

  • 基本的にprogate 1-3の内容をわかってたら、そんなに難しくないっぽい。

Progate Rails 5

バリデーションとは

  • 不正なデータがデータベースに保存されないように、データをチェックする仕組みのことをバリデーションという
  • バリデーションに引っかかった場合(不正なデータの場合)にはデータベースに保存されない
  • バリデーションの設定はモデルで設定する
  • 空文字制限する場合は以下
    class Post < ApplicationRecord
      # contentカラムに対して、空の投稿を制限するバリデーションを作成してください
      validates :content , { presence: true }
    end
  • 文字数制限する場合は以下
    class Post < ApplicationRecord
      # contentカラムに対して、文字数を制限するためのバリデーションを追加してください
      validates :content, {presence: true,length: {maximum: 140}}
    end
  • データを保存するときの post.save メソッドはデータ保存に成功した時に戻り値true、失敗した時に戻り値falseを返す仕組みになってる
  • コントローラーで、編集リクエストがきた場合にpost.saveの結果が成功したか、失敗したかでリダイレクト先を変更するようにした
  • validatesでチェックに引っかかって、post.save がfalseになった場合、直前まで入力したデータをそのままに再度入力できるようにする。そのためには、renderメソッドを使う
  • そもそも、直前まで入力してたデータが消えてしまうのは、editアクションにリダイレクトされるのが原因。
  • なので、直前まで入力していたデータをそのまま使うために、renderメソッドを使う。renderメソッドを使うと他のアクションを経由せずに、ビューを表示することができる(編集フォームを表示することができる)
  • renderメソッドを使う場合のパスの指定に注意する。render("フォルダ名/ファイル名")って書く。
  • saveメソッドで保存に失敗(バリデーションに失敗した場合)、Rails側で自動的にエラーメッセージが生成されるようになってる。
  • @post.errors.full_messagesの中に、エラー内容が配列で格納されてる
  • エラーメッセージをビューに出力させる例が以下。(このエラーメッセージを記述するHTMLの場所に戸惑った。form_tagのなかに書くっぽい。
    <% @post.errors.full_messages.each do |message| %>
       <div class="form-error">
         <%= message %>
       </div>
    <% end %>
  • 投稿に成功したら、成功したってメッセージを表示させる。そのため、Railsの特殊な変数flashを利用する。falsh[:notice] = “表示させたい文字列”
    <% if flash[:notice] %>
      <div class="flash">
        <%= flash[:notice] %>
      </div>
    <% end %>
  • 「renderメソッドを使うときは、別のアクションを経由しないで、renderメソッドで指定したビューを使える。そうすることで、renderメソッドを使っているアクションで定義してる変数を使える。」なんだけど、renderメソッドに指定されてるビューのアクションに、renderメソッドを使っているアクションで、定義している変数がなかったら、その別のアクション経由でアクセスした場合にエラーになるから、例えば、@post = Post.newって書いとけば大丈夫

Progate Rails 6

  • ユーザーの新規登録/編集ができるようにした
  • これまで投稿の機能でやってたことをユーザーに置き換えてやる
  • postsテーブルを作って投稿内容を保存してたことと同じことを、usersテーブル作ってユーザーを保存するようにする
  • 【復習】usersテーブルのマイグレーションファイルとモデルクラスを作成するコマンド
    $ rails g model User name:string email:string
  • 【復習】usersテーブルを作成する、DBに変更を反映するコマンド
    $ rails db:migrate
  • バリデーションで重複した入力を登録できないようにする場合は、uniqueness: trueをつかう
    class User < ApplicationRecord
      # nameカラムに関するバリデーションを作成してください
      validates :name,{presence: true}
      # emailカラムに関するバリデーションを作成してください
      validates :email,{presence: true ,uniqueness: true}
    end

Progate Rails 7

  • ユーザーのプロフィール画像を登録できるようにした
  • 画像ファイルは、ファイル名をテーブルに保存して、ファイル自体はpublicフォルダに保存するのが一般的
  • プロフィール画像のファイル名をusersテーブルに保存できるように、テーブルの構造を変更した。テーブルの構造を変更するまでの全体的な流れは、
  • これまで、テーブルを作成する際には、例えば rails model User image_names:string というコマンドを実行して作成していたが、マイグレーションファイルのみを作成する場合は、rails g migratione ファイル名 コマンドを使う
    $ rails g migration add_image_name_to_users
  • 作成したマイグレーションファイルに、テーブルを変更したい内容を、changeメソッドの中に記述する
  • マイグレーションファイルをDBに反映するために、使っていたコマンド「rails db:migrate」は、このchangeメソッドに記述された内容を実行するためのコマンドで、これまでに、テーブルを作ってた時も(rails model .. を実行した時も)changeメソッドが実行されていた。(rails model .. を実行した時は、changeメソッドの中身は自動で記述されてた)
  • カラムを追加するため、上記で作成したマイグレーションファイル編集するために、どんな感じでchageメソッドの中身を記述するかというと、例えば、usersテーブルに、image_nameカラム(string型)を追加したい場合は以下のように記述する。(add_column :テーブル名, :カラム名, :データ型)
    class AddImageNameToUsers < ActiveRecord::Migration[5.0]
      def change
        add_column :users,:image_name,:string
      end
    end
  • changeメソッドを記述したら、以下コマンドを実行して、テーブルに反映させる
    $ rails db:migrate
  • プロフィール画像を送信する方法(注意点は以下2点、この時点では画像フォームを作成しただけで、受け付けた画像ファイルを保存する処理は書いていないので、保存できない)

    • フォームで、画像をアップロードしたい場合、inputタグに「type="file"」を追加することで、画像ファイルを選択するボタンを表示することができる
    • 画像の送信は特殊なので、form_tagに{multipart: true}を追加する必要がある。
  • publicフォルダにふぁいるを保存する方法を知るために、まずrubyでファイルを作成する方法についてお勉強する。

    • Rubyのコードでファイルを扱うには、Rubyに元から用意されてあるFileクラスを使う
    • ファイルを作成するためには、Fileクラスのwriteメソッドを使う
    • 使い方は「File.write(ファイルの場所, ファイルの中身)」 [1] pry(main)> File.write("public/sample.txt","Hello World") => 11
  • 画像保存時の処理の流れ

    • フォームに画像ファイルが入力されたか確認する(if params[:image] 〜)
    • テーブルにファイル名を保存するようにする(@user.image_name = "#{@user.id}.jpeg”)
    • フォームに入力されたイメージを受け取る(image = params[:image])
      • 変数imageに対し、readメソッドを用いることでその画像データを取得できる
    • Fileクラスを使って、publicしたに画像ファイルを保存する
     if params[:image]
       @user.image_name = "#{@user.id}.jpeg"
       image = params[:image]
       File.binwrite("public/user_images/#{@user.id}.jpeg",image.read)
    end

Progate Rails 8

  • Progate Rails 8 は、ログイン/ログアウト機能を作るセクション
  • ログインフォームを作成したし、ログイン状態に応じてアクセス制御したり、パスワード入力するようにしたり、など。
  • パスワードを保管するカラムを作成した
    rails g migration ファイル名
  • 反映
    rails db:migrate
  • パスワードを入力する用のフォームを作った inputタグのtype属性をpasswordとすると、入力したパスワードが伏字となるパスワード用のフォームになります。

  • ログインした後に、ログイン情報を保持するためには、sessionという変数を使う ページを移動してもユーザー情報を保持し続けるために、sessionという特殊な変数を用います。sessionに代入された値は、ブラウザ(InternetExplorer, GoogleChrome等)に保存されます。sessionに値を代入すると、ブラウザはそれ以降のアクセスでsessionの値をRailsに送信します。

  • sessionの使い方

    session[:キー名] = 値
  • sessionに値を代入するときには、user_idをキーとし、値を代入します。@userが存在する場合に変数sessionに@user.idを代入することで、特定したログインユーザーの情報が保持され続けます。Progateの例は以下。
    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
  • ログインの処理ってどうやるんだっけてよく忘れちゃうけど、progateの上記コードだと、emailとpasswordの入力値を引数に、find_byして、その結果値を受け取れたら、sessionにユーザーidを格納して、ログイン完了って感じで、find_byした結果、その結果がfalseだったら、ログイン失敗って感じか。

  • ログイアウトする場合は、sessionの値を空にする ログアウトする、つまり「ログイン状態でなくする」にはsession[:user_id]の値を空にします。session[:user_id]にnilを代入することで、session[:user_id]の値を空することができます。

  • sessionの値を空にする方法

    session[:user_id] = nil
  • ログインしているユーザー名を表示させるようにする
  • ログインしているかどうかでアクセスを制御する。
  • 各コントローラの全アクションで共通する処理がある場合には、before_actionを使う。before_actionを用いることで、アクションが呼び出される際に必ずbefore_actionの処理が実行されます。これにより、全アクションで共通する処理を1箇所にまとめることができます。(applicationコントローラーの一番最初の行に以下のような感じで書く before_action 全アクションで共通する処理

  • ここで使う全てのコントローラーの全てのアクションで共通する処理は、applicationコントローラにて記述する 全てのコントローラで共通する処理はapplicaitonコントローラにまとめることができる。例えば、ログイン中のユーザーを取得するset_current_userメソッドを定義し、before_actionに指定する。これで、全コントローラの全アクションで@current_userを定義することができます。

  • application_controller.rbの記述例

    class ApplicationController < ActionController::Base
      before_action :set_current_user
      def set_current_user
        current_user = User.find_by(id: session[:user_id])
      end
    end
  • アクセス制御、ログインしていない場合、コンテンツにアクセスできないようにした。ログインしていない場合のアクセス制御は方法は、まず、application_controller.rbに、@current_userがいるかどうか条件分岐にて確認して、いない場合(nilの場合)は、flashでログインが必要ですと表示させた後、ログインページにリダイレクトされるように設定
  • そのために必要な関数を以下のような感じで定義する。(application_controller.rbに記述)
    def authenticate_user
      if @current_user == nil
        flash[:notice]="ログインが必要です"
        redirect_to("/login")
      end
    end
  • これも共通化するために、application_controller.rbに記述する。ただ、この処理は、全てのアクションに設定するわけではないので、before_action は、(applicationコントローラの先頭ではなくて)該当のコントローラーの先頭に書いて、適用したいアクションにのみ適用する。適用したいアクションはonlyで指定する before_action :authenticate_user,{only: [:index,:show,:edit,:update]}

  • ここまでは、ログインしていないユーザーのアクセス制御だったけど、つぎはログインしているユーザーのアクセス制御を行う。例えば、ログインしているユーザーに新規登録などのページは不要。application_controller.rbに以下の関数を定義して、ログインしてるユーザーに参照されたくないviewへのアクションに適用するようにする。上記authenticate_userの逆。

  • すでにログインしているユーザーのチェックは、@current_userが存在するかどうかのif文で確認
    def forbid_login_user
      if @current_user
        flash[:notice] = "すでにログインしています"
        redirect_to("/posts/index")
      end
    end

Progate Rails 8 まとめ

  • このセクションとこのセクションを含む道場コースは明日もう一度復習する。(すぐ忘れそうな要素多い)

Progate Rails 9

  • このセクションでは、投稿とユーザーを紐付ける実装のお勉強。
  • postsテーブルに誰が投稿したかがわかるようにuser_idカラムを追加した
  • (復習)マイグレーションファイルを作成
    $ rails g migration マイグレーションファイル名
  • (復習)変更内容追記
    def change
      add_column :users,:user_id,:integer
    end
  • (復習)変更内容反映
    $ rails db:migrate
  • 投稿するタイミングで、@current_user.idをpostsテーブルのuser_idカラムに保存する。
  • (復習)@current_userってどのタイミングでどうやって作成されるだっけ?
    • application_controller.rbで定義してて、session[:user_id]の中に入っているユーザーidを条件にusersテーブルからひっぱてきたユーザーを@current_userに格納している。
    • session[:user_id]に入っているユーザーidはどっから持ってきたのかというと、ログイン時もしくは、新規登録時のアクションの処理でsession[:user_id]=@user.idで値を保管してる。
    • この際の@userインスタンスは、ログイン処理や新規登録処理では、フォームにパスワードやemailの情報を入力するので、その値を使ってusersテーブルから該当ユーザーの情報を取得している
  • Railsでは、モデルクラスにインスタンスメソッドを定義することができる。
  • (復習)インスタンスメソッドとはなんだっけ???
    • クラスに定義されているメソッドで、インスタンスに対して呼び出すことのできるメソッドのこと

どのユーザーが投稿したメッセージかわかるようにするには???(投稿メッセージに投稿したユーザーを表示するようにするには???)

  • メッセージを投稿する際、投稿したユーザーの情報をpostsテーブルに保存するようにする(user_idカラム追加)
  • 投稿メッセージ(=@postインスタンス)のuser_idの情報を使って、@userインスタンスをリターンするインスタンスメソッドをpostモデルに定義する。このインスタンスメソッドを使って、投稿メッセージのビューを表示するアクションの中に@userインスタンスを定義してあげると、投稿メッセージを表示するビューで、@userインスタンスを利用することができる
    def user
      return User.find_by(id: self.user_id)
    end
  • @userを使って投稿メッセージに投稿したユーザーの情報を表示するようにする

  • 特定のユーザーが投稿した投稿インスタンスの情報を、1件のみpostsテーブルから取得する方法は、Post.find_by(user_id: @user.id) とかで取得できる。

  • 特定のユーザーが投稿した投稿インスタンスの情報を、複数postsテーブルから取得する場合はwhereメソッドを使って取得する。
  • 以下のように書くとuser_idが1の投稿が全て取得され、配列に格納される
    Post.where(user_id: 1)

ユーザー詳細ページに、そのユーザーが投稿したメッセージ一覧を出す方法???

  • (予想)ユーザーの詳細ページは、/users/:idのURLで、users#showアクションで、表示する。投稿一覧の情報を取得するには、Post.where(user_id :該当ユーザーのid)で取得する。showアクションの中に投稿一覧の配列の情報を取得するようにする????(結果としては違っててた)
    def show
      posts = Post.where(user_id: params[:id])
    end
  • Userモデルにpostsメソッド(インスタンスメソッド)を作成する。このメソッドを使うとユーザーインスタンスが投稿した投稿メッセージをpostsテーブルか取得できる。
    def posts
      return Post.where(user_id: self.id)
    end

Progate Rails 10

  • このセクションでは投稿メッセージに「いいね」をつける実装のお勉強。(取り消しもできる)
  • likeテーブルを作る
  • テーブル作成のためのマイグレーションファイルを作成
    $ rails g model テーブル名 カラム名:データ型 カラム名:データ型
    $ rails g model Like user_id:integer post_id:integer
    $ rails db:migrate
    $ rails g migrateion マイグレーションファイル名
  • likeテーブルには、user_idとpost_idが保存されている。

likeテーブルのデータを使って、どのユーザーがどの投稿にいいねしたか表示する方法???

  • likeデータを作成するためには、コントローラーが必要なので作成する。これまで、「rails g controller」コマンドで作っていたけど、今回はビューファイルが必要ないので、(rails g controllerコマンド実行したら、ビューファイルも一緒に作成される。ビューファイルが必要ないということはpostリクエストを処理するアクションのみ必要になるってこと)手動で作成する。ファイル名:likes_controller.rb
  • likesコントローラーを作ったので、/likes/:post_id/create のpostリクエストが受けたら、likes_controller.rbに定義したcreateアクションで処理される

    「いいね!」するために、createアクションの処理に何が書いてあるでしょうか???

  • (予想)ログインユーザーの情報と投稿詳細の情報( /posts/:id ページの情報)をLikeテーブルに保存する処理だな
    like = Like.new(user_id: @current_user.id,post_id: @post.id)
    if like.save
    flash[:notice] = "いいねしました"
    end
  • (結果)リダイレクトの処理抜けてた。likeじゃなくて@like。先頭に@がついている変数は、インスタンス変数。同じインスタンスのメソッドで共通利用できる

「いいね!」を取り消すために必要な処理は???

  • (予想)Likeテーブルに保存されているデータを削除する
  • 削除のpostリクエストをroutesに追加する
  • 削除のpostリクエストを受け付けた時のアクションを追加する
  • (復習)これまで出てきた削除処理って、どんな感じで書いてたっけ???
  • (復習)これまでの削除処理を振り返ってみると、データ削除する際に、postリクエストで受け付けて削除処理してた。データ削除する用のメソッドってなかったけ???
  • (復習)データベースに登録してるデータの削除方法忘れた
  • (正解)routes.rb ※抜粋 post "likes/:post_id/destroy" => "likes#destroy"

  • (正解)likes_controllerrb ※抜粋 def destroy @like = Like.find_by(user_id: @current_user.id,post_id: params[:post_id]) @like.destroy redirect_to("/posts/#{params[:post_id]}") end

  • (正解)show.html.erb ※抜粋 <%= link_to("いいね!済み","/likes/#{@post.id}/destroy",{method: "post"}) %>

「いいね!」の見た目を作るには???(ハートのアイコンにする)

  • Font Awesomeを使う。「Font Awesome」とは、様々なアイコンをフォントとして利用できるようにしたもの

  • これをlink_to()メソッドに指定してあげる。ただ、上記spanタグのようなHTMLをlink_to()メソッドに指定する場合、これまで書いてきたlink_to()メソッドとは、異なる書き方が必要

  • これまで書いてきたlink_to()メソッド
    <%= link_to("表示したい文字列","URL") %>
  • リンクとして表示した文字列をHTMLで表現したい場合は以下のように書く。
    <% link_to("URL") do %>
     <- ここにHTMLを記述 ->
    <% end %>

「いいね!」の数を取得するには???

  • (予想)投稿メッセージのidをlikeテーブルで検索をかける
    @posts = Like.where(post_id: params[:post_id])
    @posts.size
  • (正解)countメソッドを使う
    @likes_count = Like.where(post_id: 2).count

特定のユーザーが「いいね!」した投稿の一覧を表示するには???

  • (予想)いいね一覧を表示させるアクションを作成して、その処理の中にユーザーidを条件にlikeテーブルで検索した結果を表示させるようにする
    @favarit = Like.where(user_id: prams[:id])
  • (正解)routes.rb 抜粋
    get "users/:id/likes" => "users#likes"
  • (正解)users_controller.rb 抜粋
    def likes
      @user = User.find_by(id: params[:id])
      @like = Like.where(user_id: @user.id)
    end
  • (正解)likes.html.erb 抜粋
        <% @likes.each do | like | %>
          <% post = Post.find_by(id: like.post_id)  %>  
          <div class="posts-index-item">
            <div class="post-left">
              <img src="<%= "/user_images/#{post.user.image_name}" %>">
            </div>
            <div class="post-right">
              <div class="post-user-name">
                <%= link_to(post.user.name, "/users/#{post.user.id}") %>
              </div>
              <%= link_to(post.content, "/posts/#{post.id}") %>
            </div>
          </div>
        <% end %>

Progate Rails 11

  • このセクションではパスワードの安全な取り扱い方法についてお勉強する
  • パスワードを暗号化するためのgem bcryptを使って暗号化する

    どうやって暗号化するのか???

  • bcryptをインストールすると、has_secure_passwordというメソッドが使えるようになるので、これを使って暗号化する。
  • このメソッドをUserモデルクラスで使えるように設定しておくと、新規ユーザー登録の際にパスワードが勝手に暗号化されてる。Userモデルクラスに設定するのは、以下の記述にあるように記載してあげればOK
    class User < ApplicationRecord
      has_secure_password
      validates :name, {presence: true}
      validates :email, {presence: true, uniqueness: true}
      def posts
        return Post.where(user_id: self.id)
      end
    end
  • has_secure_passwordメソッドは暗号化したパスワードをpassword_digestというカラムに保存すると決まっている。
  • そのため、password_digestカラムを新しくUserテーブルに追加して、passwordカラムを削除する必要がある
  • (復習)テーブルに変更を加える時には、まずマイグレーションファイルを作成する
    $ rails g migration マイグレーションファイル名
    $ rails g migration change_users_columns
  • (復習)マイグレーションファイルを作成したら、変更内容を記述する(changeメソッドに変更内容を記述数流)
    def change
      add_column :users,:password_digest,:string
      remove_column :users,:password,:string
    end
  • (復習)変更内容を反映する
    $ rails db:migrate

password_digestカラムを新しく追加して、passwordカラムを削除したので、これまでpasswordカラムに保存してた処理をpassword_digestカラムに保存するように修正しないといけない、と思っていたけどその必要はないらしい。なぜ???

  • has_secue_passwordメソッドがpasswordに保存された値をpassword_digestに暗号化して保存するようにしてくれるらしく、問題ないとのこと。

暗号化したパスワードでログインする方法は???

  • 元々のログイン方法は、フォーム入力されたemailとpasswordがusersテーブルに存在するかチェックして、存在してたらログインできるという方法だった。パスワードが暗号化されたらどうなるか???
  • フォーム入力されたパスワードを暗号化して、保存されている暗号化されたパスワードと一致するか確認する必要がある。その処理の方法は???
  • (正解)authenticateメソッドを使う。authenticateメソッドは渡された引数を暗号化し、password_digestの値と一致するかどうかを判定できる。
  • このauthenticateメソッドはhas_secure_passwordメソッドを有効にしている場合に利用できるメソッド