質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.65%

undefined method `user' for nil:NilClass Did you mean? superエラーを解決したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 380

kousuke24

score 15

Ruby on Railsで画像を投稿し、お気に入り(like)ボタンを押した画像一覧を表示する機能を作成しています。
お気に入り画像一覧を表示するところまではできたのですが、画像のリンクをクリックした後、画像の詳細ページに飛ぶところでエラーが発生しています。

エラー内容

NoMethodError in PostsController#show
undefined method `user' for nil:NilClass Did you mean? super

def show
    @post = Post.find_by(id: params[:id])
    @user = @post.user ←ここがエラーになっています!
  end

  def destroy

コントローラー posts_controler.rb

class PostsController < ApplicationController
  before_action :authenticate_user!, only: [:new]

  def new
    @post = Post.new
    @post.photos.build
  end

  def create
    @post = Post.new(post_params)
    if @post.photos.present?
      @post.save
      redirect_to root_path
      flash[:notice] = "投稿が保存されました"
    else
      redirect_to root_path
      flash[:alert] = "投稿に失敗しました"
    end
  end

  def show
    @post = Post.find_by(id: params[:id])
    @user = @post.user
  end

  def destroy
    @post = Post.find_by(id: params[:id])
    if @post.user == current_user
      flash[:notice] = "投稿が削除されました" if @post.destroy
    else
      flash[:alert] = "投稿の削除に失敗しました"
    end
    redirect_to root_path
  end

  private

  def post_params
    params.require(:post).permit(:caption, photos_attributes: [:image]).merge(user_id: current_user.id)
  end

  def user_params
    params.require(:user).permit(:image)
  end
end

コントローラー users_controler.rb

class UsersController < ApplicationController
  def show
    @user = User.find_by(id: params[:id])
    @post = @user.posts.order(id: "DESC").page(params[:page]).per(9)
    @like = @user.likes.order(id: "DESC").page(params[:page]).per(9)
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])

    if current_user == @user
      if @user.update(user_params)
        flash[:notice] = 'プロフィール画像を変更しました'
      else
        flash.now[:danger] = 'プロフィール画像の変更に失敗しました'
      end
      @post = @user.posts.order(id: "DESC").page(params[:page]).per(9)
      render :show
    else
      redirect_to user_path
    end
  end

  def destroy
    @user = User.find_by(id: params[:id])
    @posts = Post.find_by(user_id: params[:id])
    flash[:notice] = "ユーザーを削除しました"

    if @posts.nil?
      @user.destroy
      redirect_to root_path
    else
      @posts.destroy
      @user.destroy
      redirect_to root_path
    end
  end

  private

  def user_params
    params.require(:user).permit(:image)
  end
end

ビュー

<div class="container">
  <h3 class="text-center text-secondary mb-4">ユーザー情報</h3>

  <div class="offset-sm-3 col-sm-6">
    <div class="offset-sm-3 col-sm-6 text-center">
      <h4 class="mb-3"><%= @user.name %></h4>
      <%= form_for(@user) do |f| %>
        <% if @user.image? %>
          <%= image_tag @user.image.thumb.url, class: "round-img" %>
        <% else %>
          <%= image_tag "/assets/default.jpg", class: "round-img" %>
        <% end %>
    </div>
  </div>

  <div class="offset-sm-4 col-sm-4 offset-sm-4 text-center">
    <% if @user == current_user %>
      <button type="button" class="btn btn-outline-secondary rounded-pill mt-3">
        <%= f.file_field :image, accept: 'image/jpg,image/gif,image/png' %>
      </button>
        <%= f.submit "プロフィール画像変更", class: 'btn btn-outline-dark mt-1 form-control' %>
        <%= link_to "登録情報編集", edit_user_registration_path, class: "btn btn-secondary mt-3 form-control" %>
        <%= link_to "退会", user_destroy_path, method: :delete, data: { confirm: "本当に退会しますか?" }, class: "btn btn-danger mt-3 form-control" %>
      <% end %>
      <br>
    <% end %>
  </div>
  <hr>

</div>

<div class="photos-parent text-center">
  <h5><i class="fas fa-paw"></i> <%= @user.name %>の投稿画像</h5>
  <% @post.each do |post| %>
    <%= link_to(post_path(post)) do %>
      <div class="photos-children">
        <%= image_tag post.photos.first.image.url(:medium) %>
      </div>
    <% end %>
  <% end %>
</div>

<div class="photos-parent text-center">
  <h5><i class="fas fa-paw"></i> <%= @user.name %>のお気に入り画像</h5>
  <% @like.each do |like| %>
    <%= link_to(post_path(@post)) do %>
      <div class="photos-children">
        <%= image_tag like.post.photos.first.image.url(:medium) %>
      </div>
    <% end %>
  <% end %>
</div>

<div class="paginate-parent">
  <div class="paginate-children mt-3">
    <%= paginate @post %>
  </div>
</div>

ルーティング

Rails.application.routes.draw do
  devise_for :users,
    controllers: { registrations: 'registrations', omniauth_callbacks: 'users/omniauth_callbacks' }

  root to: 'tops#index'
  get 'tops/show', to: 'tops#show'

  get '/users/:id', to: 'users#show', as: :user
  patch '/users/:id', to: 'users#update'
  delete '/users/:id', to: 'users#destroy', as: :user_destroy

  resources :posts, only: %i(new create show destroy) do
    resources :photos, only: %i(create)
    resources :likes, only: %i(create destroy)
  end
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

説明不足等ありましたら遠慮なく言ってください。
ご教授頂ければ幸いです。よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

   <%= link_to(post_path(@post)) do %>

ここが問題です。
ここでの@postはuserが投稿したものの集合です。
(複数なのに変数名が単数形なのが勘違いの原因の一つかなとは思います…)

正しくは、

    <%= link_to(post_path(like.post)) do %>

かな、と推測します。


  def show
    @post = Post.find(params[:id])
    @user = @post.user
  end

私見ですがこのケースでは、
find_byよりもfindを使って、異常入力の場合に404 NotFound返した方がよいと思います。

find_byを使うのならば、nilが返却された場合にどうするべきなのか考える必要があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/30 16:44

    解決しました!
    詳細に説明も書いて下さりありがとうございます。
    とてもわかりやすく、勉強になりました!

    キャンセル

0

@postがnilになってませんか。
チェックしてみてください

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/30 11:08

    すいません、@postのnilをチェックするにはどこに、何を記入すれば良いのでしょうか?
    恥ずかしながら初心者でして、、、
    よろしければ教えて頂きたいです!

    キャンセル

  • 2019/09/30 12:03

    テスト的に、その変数の内容を表示するコードを書いてみてはどうでしょう

    キャンセル

  • 2019/09/30 16:22

    usersのshow.html.erbに
    <%= image_tag like.post.photos.first.image.url(:medium) if @post.nil? %>
    if @post.nil?と追加した結果、画像が表示されなくなりました。
    正直、y_waiwaiさんから教えて頂いたことが正しくできているのかわかっていません。これであっていますでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.65%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる