Webエンジニア目指して#43
どうもアニメマンです
ウマ娘めちゃくちゃ面白いですね。1期スルーしてましたが最近の盛り上がりがすごくて見てみたらハマりました。スマホゲーはやらないけど...
さあやっていきましょうProgateのRails IXです。
の前に、Rails道場編IIIの反省を書こうと思いましたが特にありませんでした。括弧の自動有力に慣れてしまってて、Progateでは{}が自動で閉じられなくてsintax errを出すみたいなしょうもないのくらいですね
あと、ログインユーザー本人のアカウント情報以外編集出来ないようにするメソッド作りましたが、postアクションだけ何故かリダイレクトせず、no routeエラーを返すようで困りましたが次触る時に調べることとします →ほっとくのはまずいと思って探ってみたらわかりました!!!!
エラー画像
よく見たら[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}") %>
結果
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テーブルの情報を持ってこられる
結果
whereメソッドを使ってユーザー詳細ページに投稿を表示する
whereメソッドとは、SQLでいうwhereのようにテーブルに対し特定のカラムでフィルターをかけ、そのレコード群を配列として返すもの。
rails consoleでの例
これを使って、対象のユーザー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 %>
結果
投稿詳細画面で投稿者以外に編集制限をかける
基本的にはユーザー編集画面と同じ処理
せっかくなので@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
結果
これでRails IXはおわり!ではでは