Webエンジニア目指して#43

どうもアニメマンです

ウマ娘めちゃくちゃ面白いですね。1期スルーしてましたが最近の盛り上がりがすごくて見てみたらハマりました。スマホゲーはやらないけど...

さあやっていきましょうProgateのRails IXです。

の前に、Rails道場編IIIの反省を書こうと思いましたが特にありませんでした。括弧の自動有力に慣れてしまってて、Progateでは{}が自動で閉じられなくてsintax errを出すみたいなしょうもないのくらいですね

あと、ログインユーザー本人のアカウント情報以外編集出来ないようにするメソッド作りましたが、postアクションだけ何故かリダイレクトせず、no routeエラーを返すようで困りましたが次触る時に調べることとします →ほっとくのはまずいと思って探ってみたらわかりました!!!!

エラー画像 f:id:misokatsu_sand:20210417045805p:plain よく見たら[GET]ってあるんですよね。updateメソッドはpostでroutingしてあるのでgetはおかしい
考えてみたらURLの直接入力はget扱いになるので当然のエラーでした。postは特定の処理しないとできないからね

get用のrouting作ってダミーactionで不正な処理として適当なページにリダイレクトさせようかな、と考えましたが、意図しないURLは全部こうなるんだから気にしないことにしました。

はい、というわけで今度こそRails IXやっていきます

目標

投稿とユーザーの紐付け、対応データの表示

投稿テーブルにユーザーidカラムを追加する

いつもの通りmigrationファイル作ってadd_columnしてdb:migrateからのvalidatesで{presence:true}書いてfinish

ユーザーidは数字のため型はintegerにする

ここで1点反省、最初の方に"post"でrails g controllerを実行してpost-modelが生成されているが、テーブル名はpostsで生成されていてめちゃくちゃ紛らわしい。
なので次回からはcontrollerやmodelを作るときは複数形で統一したい

投稿actionにログイン中のユーザーidを付与

def save
  @post=Post.new(
    message: params[:message],
    user_id: @current_user.id
  )

投稿詳細にユーザー情報を表示する

post.controller

def details
    @post=Post.find_by(id: params[:id])
    @user=User.find_by(id: @post.user_id)
  end
以下略

post/details.html.erb

<img src="<%= "/user_images/#{@user.image_name}" %>" >
<%= link_to(@user.name,"/users/#{@user.id}") %>

結果

f:id:misokatsu_sand:20210418161729p:plain

postモデルにインスタンスメソッドを定義する

class Post < ApplicationRecord
  def user
    return User.find(self.user_id)
  end
以下略

selfメソッドによって、インスタンスの値を利用できるため、
レコードを読み込ませた@postインスタンスに対して@post.userと扱うことで簡単にUserテーブルを参照できる

投稿一覧にユーザー情報を表示する

post/index.html.erb

<% @posts.each do |post| %>
  <img src="<%= "/user_images/#{post.user.image_name}" %> ">
  <%= link_to(post.user.name,"/post/#{post.user.id}") %>
  <%= link_to(post.message,"/post/#{post.id}") %>
<% end %>

先程の@post.userによって、@userを定義しなくても以下のように@postだけでUserテーブルの情報を持ってこられる

結果 f:id:misokatsu_sand:20210421060208p:plain

whereメソッドを使ってユーザー詳細ページに投稿を表示する

whereメソッドとは、SQLでいうwhereのようにテーブルに対し特定のカラムでフィルターをかけ、そのレコード群を配列として返すもの。
rails consoleでの例 f:id:misokatsu_sand:20210421062607p:plain

これを使って、対象のユーザーidの投稿を取得するインスタンスメソッドをUserモデルに定義する

class User < ApplicationRecord
  def posts
    return Post.where(user_id: self.id)
  end
以下略

そしてユーザー詳細viewで@user.postsの配列に対してeachメソッドを使って投稿データを並べる

<% @user.posts.each do |post| %>
  <img src="<%= "/user_images/#{post.user.image_name}" %> ">
  <%= link_to(post.user.name,"/post/#{post.user.id}") %>
  <%= link_to(post.message,"/post/#{post.id}") %>
<% end %>

結果 f:id:misokatsu_sand:20210421182928p:plain

投稿詳細画面で投稿者以外に編集制限をかける

基本的にはユーザー編集画面と同じ処理
せっかくなので@current_user.id@post.user.idで照合させる

post/details.html.erb

<% if @current_user.id == @post.user.id %>
  <%= link_to("編集","/post/#{@post.id}/edit") %>
  <%= link_to("削除","/post/#{@post.id}/delete",{method:"post"}) %>
<% end %>

post.controller

before_action :check_incorrect_user,{only:[:edit,:update,:delete]}

  def check_incorrect_user
    @post=Post.find(params[:id])
    if @current_user.id != @post.user.id
      flash[:notice]="権限がありません"
      redirect_to("/post/index")
    end
  end

結果

f:id:misokatsu_sand:20210424052545g:plain

これでRails IXはおわり!ではでは