いいねボタンを作成するためのcreateアクションを作成

初めに

  • Progateを学習中に躓いたところを中心にアウトプットするのと同時に備忘録がてらに記事を書いていきます!

現状

  • likes_controller内にcreateアクションを定義したが中身は空のまま。

  • createアクションに関するルーティングは

post "likes/:post_id/create" => "likes#create"

自分が書いたコード

likes_controller

class LikesController < ApplicationController
  before_action :authenticate_user
def create
    @like = Like.new(user_id :@current_user.id, post_id :@post.id
    @like.save   
    redirect_to("/posts/#{params[:post_id]}")
  end
  • authenticate_userはapplicarion_controllerで
def authenticate_user
    if @current_user == nil
      flash[:notice] = "ログインが必要です"
      redirect_to("/login")
    end
  end

としている。

  • @postが定義されていないのでエラーの対象となる。

実際のコード

likes_controller
def create
    @like = Like.new(user_id :@current_user.id, post_id :params[:post_id])
    @like.save   
    redirect_to("/posts/#{params[:post_id]}")
  end
  • いいね!を作るためにはユーザーのidと投稿のidの2つが必要。

  • 例えばLike.new(user_id: 1, post_id: 2)となるとuser1がpost1にいいねしたというコードになる。

  • post_id :@post.id→post_id :params[:post_id]に変更した。

  • createのルーティングよりpost "likes/:post_id/create" => "likes#create"からpost_idは送られていて、 Like.newに入れれば良いのでpost_id :params[:post_id]となる

結語

  • post_idの値はルーティンで記載されてあるURLのpost_idに含まれている。

  • paramsはURLの値を捕まえる役割がある。

before_actionを特定の場所に効かせるために

初めに

  • application_controllerで以下のものを定義して、ログインしていないユーザーに対してアクセス制限をかけるようにした。
def authenticate_user
   if @current_user == nil
     flash[:notice] = "ログインが必要です"
     redirect_to("/login")
   end
 end
  • 今回はposts_controllerの全てのアクション、users_controllerのindex,show,update,editアクションのみに制限をかけたい

問題

  • アクセス制限をかけたくないhomes_controllerのtop,aboutアクションにもアクセス制限がかかっていた。

コード

application_controller
class ApplicationController < ActionController::Base
before_action :set_current_user
before_action:authenticate_user

 def set_current_user
   @current_user = User.find_by(id: session[:user_id])
 end
 
 def authenticate_user
   if @current_user == nil
     flash[:notice] = "ログインが必要です"
     redirect_to("/login")
   end
 end
end
posts_controller
class PostsController < ApplicationController
  before_action :authenticate_user
                
  def index
    @posts = Post.all.order(created_at: :desc)
  end
  
  def show
    @post = Post.find_by(id: params[:id])
  end
  
  def new
    @post = Post.new
  end
  
  def create
    @post = Post.new(content: params[:content])
    if @post.save
      flash[:notice] = "投稿を作成しました"
      redirect_to("/posts/index")
    else
      render("posts/new")
    end
  end
  
  def edit
    @post = Post.find_by(id: params[:id])
  end
  
  def update
    @post = Post.find_by(id: params[:id])
    @post.content = params[:content]
    if @post.save
      flash[:notice] = "投稿を編集しました"
      redirect_to("/posts/index")
    else
      render("posts/edit")
    end
  end
  
  def destroy
    @post = Post.find_by(id: params[:id])
    @post.destroy
    flash[:notice] = "投稿を削除しました"
    redirect_to("/posts/index")
  end
  
end
users_controller
class UsersController < ApplicationController
  before_action :authenticate_user ,{only:[:index,:show,:edit,:update]}
  
  def index
    @users = User.all
  end
  
  def show
    @user = User.find_by(id: params[:id])
  end
  
  def new
    @user = User.new
  end
  
  def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      image_name:"default_user.jpg",
      password: params[:password]
      )
    if @user.save
     
      session[:user_id] = @user.id
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      @email = params[:email]
      @password = params[:password]
      @name = params[:name]
      render("users/new")
    end
  end
  
  def edit
    @user = User.find_by(id: params[:id])
  end
  
  def update
    @user = User.find_by(id: params[:id])
    @user.name = params[:name]
    @user.email = params[:email]
   if params[:image]
    @user.image_name = "#{@user.id}.jpg"
    image = params[:image]
    File.binwrite("public/user_images/#{@user.image_name}",image.read)
   end
    if @user.save
      flash[:notice] = "ユーザー情報を編集しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/edit")
    end
  end
  def login_form
  end
  
  def login
    @user = User.find_by(password: params[:password], email: params[:email])
    if @user
     session[:user_id] = @user.id
     flash[:notice] = "ログインしました"
     redirect_to("/posts/index")
    else
      @email = params[:email]
      @password = params[:password]
      @error_message = "メールアドレスまたはパスワードが間違っています"
     render("users/login_form")
    end
  end
  def logout
      session[:user_id] = nil
      flash[:notice] = "ログアウトしました"
      redirect_to("/login")
    
  end
  
end
home_controller
class HomeController < ApplicationController
  def top
    
  end
  
  def about
    
  end
end

原因

  • application_controllerでbefore_action:authenticate_userを定義しているために全てのcontrollerにアクセス制限をかけてしまっていた。

  • application_controllerでbefore_action:authenticate_userを削除してアクセス制限をかけたいcontrollerでbefore_action:authenticateを定義する。

結語

  • application_controllerでbefore_actionを定義してしまうと全てのcontrollerに影響を与えてしまう

  • application_controllerで定義したメソッドは他のcontrollerで利用できるので 今回はアクセス制限をかけたいcontroller内でbefore_actionを定義しなくてはいけない。

before_actionを特定の場所に効かせるために

初めに

  • application_controllerで以下のものを定義して、ログインしていないユーザーに対してアクセス制限をかけるようにした。
def authenticate_user
   if @current_user == nil
     flash[:notice] = "ログインが必要です"
     redirect_to("/login")
   end
 end
  • 今回はposts_controllerの全てのアクション、users_controllerのindex,show,update,editアクションのみに制限をかけたい

問題

  • アクセス制限をかけたくないhomes_controllerのtop,aboutアクションにもアクセス制限がかかっていた。

コード

application_controller
class ApplicationController < ActionController::Base
before_action :set_current_user
before_action:authenticate_user

 def set_current_user
   @current_user = User.find_by(id: session[:user_id])
 end
 
 def authenticate_user
   if @current_user == nil
     flash[:notice] = "ログインが必要です"
     redirect_to("/login")
   end
 end
end
posts_controller
class PostsController < ApplicationController
  before_action :authenticate_user
                
  def index
    @posts = Post.all.order(created_at: :desc)
  end
  
  def show
    @post = Post.find_by(id: params[:id])
  end
  
  def new
    @post = Post.new
  end
  
  def create
    @post = Post.new(content: params[:content])
    if @post.save
      flash[:notice] = "投稿を作成しました"
      redirect_to("/posts/index")
    else
      render("posts/new")
    end
  end
  
  def edit
    @post = Post.find_by(id: params[:id])
  end
  
  def update
    @post = Post.find_by(id: params[:id])
    @post.content = params[:content]
    if @post.save
      flash[:notice] = "投稿を編集しました"
      redirect_to("/posts/index")
    else
      render("posts/edit")
    end
  end
  
  def destroy
    @post = Post.find_by(id: params[:id])
    @post.destroy
    flash[:notice] = "投稿を削除しました"
    redirect_to("/posts/index")
  end
  
end
users_controller
class UsersController < ApplicationController
  before_action :authenticate_user ,{only:[:index,:show,:edit,:update]}
  
  def index
    @users = User.all
  end
  
  def show
    @user = User.find_by(id: params[:id])
  end
  
  def new
    @user = User.new
  end
  
  def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      image_name:"default_user.jpg",
      password: params[:password]
      )
    if @user.save
     
      session[:user_id] = @user.id
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      @email = params[:email]
      @password = params[:password]
      @name = params[:name]
      render("users/new")
    end
  end
  
  def edit
    @user = User.find_by(id: params[:id])
  end
  
  def update
    @user = User.find_by(id: params[:id])
    @user.name = params[:name]
    @user.email = params[:email]
   if params[:image]
    @user.image_name = "#{@user.id}.jpg"
    image = params[:image]
    File.binwrite("public/user_images/#{@user.image_name}",image.read)
   end
    if @user.save
      flash[:notice] = "ユーザー情報を編集しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/edit")
    end
  end
  def login_form
  end
  
  def login
    @user = User.find_by(password: params[:password], email: params[:email])
    if @user
     session[:user_id] = @user.id
     flash[:notice] = "ログインしました"
     redirect_to("/posts/index")
    else
      @email = params[:email]
      @password = params[:password]
      @error_message = "メールアドレスまたはパスワードが間違っています"
     render("users/login_form")
    end
  end
  def logout
      session[:user_id] = nil
      flash[:notice] = "ログアウトしました"
      redirect_to("/login")
    
  end
  
end
home_controller
class HomeController < ApplicationController
  def top
    
  end
  
  def about
    
  end
end

原因

  • application_controllerでbefore_action:authenticate_userを定義しているために全てのcontrollerにアクセス制限をかけてしまっていた。

  • application_controllerでbefore_action:authenticate_userを削除してアクセス制限をかけたいcontrollerでbefore_action:authenticateを定義する。

結語

  • application_controllerでbefore_actionを定義してしまうと全てのcontrollerに影響を与えてしまう

  • application_controllerで定義したメソッドは他のcontrollerで利用できるので 今回はアクセス制限をかけたいcontroller内でbefore_actionを定義しなくてはいけない。

ヘッダーのログアウトのリンクを押してもログアウトリンクに遷移しない原因

初めに

  • Progateを学習して躓いたところのアウトプットをすることで学習効率を上げる目的とともに備忘録として記事を書きます

問題

  • ヘッダーのログアウトのリンクを押してもログアウトリンクに遷移しない

考えられること

  • ログアウトリンクに誤りがある

  • ログアウトに関するルーティングに誤りがある

  • user_controllerのlogoutアクションに誤りがある

関連するコード

routes.rb
Rails.application.routes.draw do
  post "logout" => "users#logout"
  get "login" => "users#login_form"
  post "login" => "users#login"
  
  post "users/:id/update" => "users#update"
  get "users/:id/edit" => "users#edit"
  post "users/create" => "users#create"
  get "signup" => "users#new"
  get "users/index" => "users#index"
  get "users/:id" => "users#show"

  get "posts/index" => "posts#index"
  get "posts/new" => "posts#new"
  get "posts/:id" => "posts#show"
  post "posts/create" => "posts#create"
  get "posts/:id/edit" => "posts#edit"
  post "posts/:id/update" => "posts#update"
  post "posts/:id/destroy" => "posts#destroy"
  
  get "/" => "home#top"
  get "about" => "home#about"
end
users_controller
class UsersController < ApplicationController
  def index
    @users = User.all
  end
  
  def show
    @user = User.find_by(id: params[:id])
  end
  
  def new
    @user = User.new
  end
  
  def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      image_name:"default_user.jpg",
      password: params[:password]
      )
    if @user.save
     
      session[:user_id] = @user.id
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      @email = params[:email]
      @password = params[:password]
      @name = params[:name]
      render("users/new")
    end
  end
  
  def edit
    @user = User.find_by(id: params[:id])
  end
  
  def update
    @user = User.find_by(id: params[:id])
    @user.name = params[:name]
    @user.email = params[:email]
   if params[:image]
    @user.image_name = "#{@user.id}.jpg"
    image = params[:image]
    File.binwrite("public/user_images/#{@user.image_name}",image.read)
   end
    if @user.save
      flash[:notice] = "ユーザー情報を編集しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/edit")
    end
  end
  def login_form
  end
  
  def login
    @user = User.find_by(password: params[:password], email: params[:email])
    if @user
     session[:user_id] = @user.id
     flash[:notice] = "ログインしました"
     redirect_to("/posts/index")
    else
      @email = params[:email]
      @password = params[:password]
      @error_message = "メールアドレスまたはパスワードが間違っています"
     render("users/login_form")
    end
  end
  def logout
      session[:user_id] = nil
      flash[:notice] = "ログアウトしました"
      redirect_to("/login")
    
  end
  
end
application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>TweetApp</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <header>
      <div class="header-logo">
        <%= link_to("TweetApp", "/") %>
      </div>
      <ul class="header-menus">
   
        <li>
          <% if session[:user_id] %>
          現在ログインしているユーザーのid: 
          <%= session[:user_id] %>
       
          <li>
          <%= link_to("投稿一覧", "/posts/index") %>
          </li>
          <li>
            <%= link_to("新規投稿", "/posts/new") %>
          </li>
          <li>
            <%= link_to("ユーザー一覧", "/users/index") %>
          </li>
          <li>
            <%= link_to("ログアウト","/logout")%>
          </li>
          <% else %>
          <li>
           <%= link_to("TweetAppとは", "/about") %>
          </li>
          <li>
           <%= link_to("新規登録", "/signup") %>
          </li>
          <li>
           <%= link_to("ログイン", "/login") %>
          </li>
          
          <%end%>
        </li>
      </ul>
    </header>

    <% if flash[:notice] %>
      <div class="flash">
        <%= flash[:notice] %>
      </div>
    <% end %>
    
    <%= yield %>
  </body>
</html>

原因

  • ログアウトリンクに{method: "post"}が記述されていなかった。

  • <%= link_to("ログアウト","/logout",{method: "post"})%>

  • {method: "post"}がないことでログアウトに関連するpost "/logout" =>"users#logout"を実行できなかったと考えられる

  • link_toではHTTP methodを指定してあげないとgetになってしまうので get "/logout" =>"user#logout"を探してしまうことになってしまう

結語

  • link_toはmethodを指定しなければHTTPメソッドをgetとしてしまう

ユーザーを特定する

初めに

Progateを学習して躓いたところを中心にアウトプットし、備忘録としても活用していきます。

ログインするユーザーを特定していく。

  • find_byメソッドを利用していく。

  • 今回はpasswordとemailの2つからユーザーを特定していく

  • ユーザーテーブルからフォームで入力された値と一致するユーザーを見つけ出し、@userに代入する

    users_controller
def login
    @user = User.find_by(email: params[:email], password: params[:password])
end

if文を使って存在するユーザーなのか、存在しないユーザーなのか判別する。

users_controller
def login
    @user = User.find_by(email: params[:email], password: params[:password])
 if @user
    flash[:notice] = "ログインしました"
 redirect_to("/posts/index")
 else
   render("users/login_form")
    
end
  • if @user ではemailとpasswordが一致するユーザーがいるのならばというコード。

  • 一致するユーザーがいた場合、flash[:notice] = "ログインしました"が表示される。

  • そして投稿一覧ページに遷移する。

  • もし一致するユーザーがいなければ、ログインページに戻る。

ユーザーがいなかった場合、エラーメッセージを表示させる

users_controller
def login
    @user = User.find_by(email: params[:email], password: params[:password])
 if @user
    flash[:notice] = "ログインしました"
 redirect_to("/posts/index")
 else
   @error_message = "メールアドレスまたはパスワードが違います"
   render("users/login_form")
    
end
  • バリデーションによって表示させるエラーメッセージではないので、@error_message = "メールアドレスまたはパスワードが違います"のように 自作でエラーメッセージを作る。
login_form.html.erb
 <div class="form-body">
        <% if @error_message %>
          <div class="form-error">
           <%= @error_message %>
          </div>
        <% end %>
        <%= form_tag("/login") do %>
          <p>メールアドレス</p>
          <input name="email" value="<%= @email %>">
          <p>パスワード</p>
          <input type="password" name="password" value="<%= @password %>">
          <input type="submit" value="ログイン">
        <% end %>
      </div>
  • reder先のlogin_form.htmlに@error_messageを貼り付け、メールアドレスとパスワードが一致しない場合はエラーメッセージが表示できるようにす る。

結語

  • find_byメソッドを利用して登録したユーザーを見つけ出す。

  • if 文を利用して登録済みユーザーが未登録ユーザーなのかを判別する。

  • flashメッセージを利用してログインができたことを表示させる。

  • バリデーションではないエラーメッセージの場合は@error_messageのような自らエラー表示用のインスタン変数を作り出し、メッセージを記述し、 表示させたいビューに貼り付ける。

ユーザー登録時に初期画像を設定する

初めに

  • Progateを学習して躓いたところをアウトプットすることで学習効率を上げるとともに備忘録がてらに日記を書いていきます。

結論

  • ユーザー情報を入力する空箱の中に初期画像の情報を入れておく

前提

  • usersテーブルにimage_nameカラムを追加しておく

 ターミナルにてrails g migration users image_name stringを行う  生成したマイグレーションファイルにadd_column :テーブル名, :カラム名, :データ型でchangメソッドの中に記載を行う  *rails db:migrateを行う

ユーザー登録する際に初期の画像を設定するために

  • public/user_imagesに初期画像のdefault_user.jpgを用意する

  • ユーザー登録時にimage_nameカラムの値がdefalt_user.jpgになるようにする

def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      image_name: "default_user.jpg"
    )
    if @user.save
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/new")
    end
  end

結語

  • User.newという空箱の中に image_nameカラムを入れ、その値にすでに決まっているdefault_user.jpgを入れることでデフォルトで画像が挿入できる

ユーザー登録時に初期画像を設定する

初めに

  • Progateを学習して躓いたところをアウトプットすることで学習効率を上げるとともに備忘録がてらに日記を書いていきます。

結論

  • ユーザー情報を入力する空箱の中に初期画像の情報を入れておく

前提

  • usersテーブルにimage_nameカラムを追加しておく

 ターミナルにてrails g migration users image_name stringを行う  生成したマイグレーションファイルにadd_column :テーブル名, :カラム名, :データ型でchangメソッドの中に記載を行う  *rails db:migrateを行う

ユーザー登録する際に初期の画像を設定するために

  • public/user_imagesに初期画像のdefault_user.jpgを用意する

  • ユーザー登録時にimage_nameカラムの値がdefalt_user.jpgになるようにする

def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      image_name: "default_user.jpg"
    )
    if @user.save
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/new")
    end
  end

結語

  • User.newという空箱の中に image_nameカラムを入れ、その値にすでに決まっているdefault_user.jpgを入れることでデフォルトで画像が挿入できる