kqkky1101
@kqkky1101

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

【rails7】undefined method `image' for nil:NilClassの解決方法

Q&A

Closed

解決したいこと

Ruby on railsで簡単なSNSを作っているのですが、Active Storageでプロフィール画像を実装したところ、投稿の詳細画面(/posts/:id/show)の画面で以下のエラーが表示されます。

投稿一覧画面(/posts/index)ではプロフィール画像が表示されるため、ユーザーのプロフィール画像がnilになっていることが原因ではなさそうです。
よろしくお願いいたします。

undefined method `image' for nil:NilClass'.freeze;@output_buffer.append=( image_tag @user.image );@output_buffer.safe_append='

問題のエラーコード

<%= image_tag @user.image %>でエラーが発生しているようです。

<div class="main posts-show">
  <div class="container">
    <div class="posts-show-item">
      <div class="post-user-name">
      <%= image_tag @user.image %>
        <%= link_to(@user.name,"/users/#{@user.id}") %>
        <div class="posts-following-btn">
          <%# フォローボタン %>
          <% if current_user != @user %>
            <% if current_user.following?(@user) %>
              <%= button_to 'フォロー外す', user_relationships_path(@user.id), method: :delete %>
            <% else %>
              <%= button_to 'フォローする', user_relationships_path(@user.id), method: :POST %>
            <% end %>
          <% end %>
        </div>
      </div>
      
      <p>
        <%= @post.content %>
      </p>
      <div class="post-time">
        <%= @post.created_at %>
      </div>


      <% if Like.find_by(user_id: current_user.id, post_id: @post.id)  %>
        <%= link_to("/likes/#{@post.id}/destroy", data:{turbo_method: :post}) do %>
          <span class="fa fa-heart liked-btn"></span>
        <% end %>
      <% else %>
        <%= link_to("/likes/#{@post.id}/create", data:{turbo_method: :post}) do %>
          <span class="fa fa-heart unliked-btn"></span>
        <% end %>
      <% end %>

      <%= @likes_count %>

      <% if @post.user_id==current_user.id %>
        <div class="post-menus">
          <%= button_to "編集", "/posts/#{@post.id}/edit",{method:"get",class: "button_to2"} %>
          <%= button_to "削除", "/posts/#{@post.id}/destroy", {method:"post" ,class: "button_to2"} %>
        </div>
      <% end %>
    </div>
  </div>
</div>
      <% if user_signed_in? %>
        <%= form_with model: [@post, @comment] do |f| %>
          <%= f.text_area :comment_content,placeholder: 'コメントする' %>
          <%= f.submit 'SEND' %>
        <% end %>
      <% end %>

        <h2>コメント一覧</h2>
          <% @comments.each do |c| %>
            <%= c.comment_content %>
              <hr>
          <% end %>

posts_controller.rb

class PostsController < ApplicationController
  before_action :ensure_correct_user,{only:[:edit,:update,:destroy]}


  def index
    @posts=Post.all.order(created_at: :desc)
  end

  def show 
    @post=Post.find_by(id: params[:id])
    @likes_count=Like.where(post_id: @post.id).count
    @comments = @post.comments.includes(:user) 
    @comment = Comment.new 
  end

  def new
    @post=Post.new
  end

  def create
    @post=Post.new(
      content: params[:content],
      user_id: current_user.id
    )
    if @post.save
      flash[:notice]="投稿を作成しました"
      redirect_to("/posts/index")
    else
      render("posts/new",status: :unprocessable_entity)
    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", status: :unprocessable_entity
    end
  end

  def destroy
    @post=Post.find_by(id: params[:id])
    @post.destroy
    flash[:notice]="投稿を削除しました"
    redirect_to "/posts/index"
  end

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

  private
  def post_params
    params.require(:post).permit(:post_content)
  end


end

user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  before_create :default_image
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  validates :introduction, presence: false, length: { maximum: 50 } # 自己紹介の最高文字数は50文字

  has_one_attached :image

  def default_image
    if !self.image.attached?
      self.image.attach(io: File.open(Rails.root.join('app', 'assets', 'images', 'デフォルト.png')), filename: 'default-image.png', content_type: 'image/png')
    end
  end  
  #validates :image, content_type: { in: %w[image/jpeg image/gif image/png],
  #message: "有効なフォーマットではありません" },
  #size: { less_than: 20.megabytes, message: " 20MBを超える画像はアップロードできません" }

  def posts
    return Post.where(user_id: self.id)
  end

  has_many :follower, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
  has_many :followed, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
  has_many :following_user, through: :follower, source: :followed # 自分がフォローしている人
  has_many :follower_user, through: :followed, source: :follower # 自分をフォローしている人


  # ユーザーをフォローする
  def follow(user_id)
    follower.create(followed_id: user_id)
  end

  # ユーザーのフォローを外す
  def unfollow(user_id)
    follower.find_by(followed_id: user_id).destroy
  end

  # フォローしていればtrueを返す
  def following?(user)
    following_user.include?(user)
  end

  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy

end

補足情報

ruby 3.1.2p20
Rails 7.0.4

0

3Answer

<%# フォローボタン %>
関係ないかもしれませんが、上記に#でコメントになっていますが、あえてでしょうか?

1Like

Comments

  1. @kqkky1101

    Questioner

    申し訳ございません。こちら単純なミスです。
    なおエラーは変わっておりません。
  2. 失礼しました。
  3. コントローラーのshowメソッドに@userを追加してみてはいかがでしょうか。。。
  4. def posts
    return Post.where(user_id: self.id)
    end

    上記はpostsと複数形になっているため、indexメソッドでは@postsで紐づいているのかもしれません。

    def post

    end

    で処理を追加してみてはいかがでしょうか。
    詳しくはわからないので、すみません。
  5. @kqkky1101

    Questioner

    ```
    @user=User.find_by(id: params[:id])
    ```
    をshowメソッドに追加したのですが、エラー表示は全く変わらずです。。
  6. @kqkky1101

    Questioner

    user.rbに

    def post
    end

    を追加したのですが、エラー変わらずです。。
  7. <%= image_tag @user.image %>

    <%= image_tag '#{@user.image}' %>

    上記のようにしたらいかがでしょうか。。。
  8. @kqkky1101

    Questioner

    試したところ、エラー表示画面は以下の通りで、
    Sprockets::Rails::Helper::AssetNotFound in Posts#show
    ターミナルに出力されるエラー分は以下となります。
    ActionView::Template::Error (The asset "" is not present in the asset pipeline.
    ):
    2: <div class="container">
    3: <div class="posts-show-item">
    4: <div class="post-user-name">
    5: <%= image_tag '#{@user.image}' %>
    6: <%= link_to(@user.name,"/users/#{@user.id}") %>
    7: <div class="posts-following-btn">
    8: <% if current_user != @user %>

    app/views/posts/show.html.erb:5


    また、<div class="main posts-show">
    <div class="container">
    <div class="posts-show-item">
    <div class="post-user-name">
    <%= image_tag '#{@user.image}' %>
    <%= link_to(@user.name,"/users/#{@user.id}") %>
    <div class="posts-following-btn">
    <% if current_user != @user %>
    <% if current_user.following?(@user) %>
    <%= button_to 'フォロー外す', user_relationships_path(@user.id), method: :delete %>
    <% else %>
    <%= button_to 'フォローする', user_relationships_path(@user.id), method: :POST %>
    <% end %>
    <% end %>
    </div>
    </div>
    を消すとページは接続されます。。
  9. @kqkky1101

    Questioner

    production.rbでconfig.assets.compile = trueにして、.to_sをつけると、
    ActionView::Template::Error (undefined method `image' for nil:NilClass

    '.freeze;@output_buffer.append=( image_tag @user.image.to_s );@output_buffer.safe_append='
    ^^^^^^):
    2: <div class="container">
    3: <div class="posts-show-item">
    4: <div class="post-user-name">
    5: <%= image_tag @user.image.to_s %>
    6: <%= link_to(@user.name,"/users/#{@user.id}") %>
    7: <div class="posts-following-btn">
    8: <% if current_user != @user %>

    app/views/posts/show.html.erb:5

    となり、変わらず
    "#{@user.image.to_s}"にしても
    ActionView::Template::Error (undefined method `image' for nil:NilClass

    '.freeze;@output_buffer.append=( image_tag "#{@user.image.to_s}" );@output_buffer.safe_append='
    ^^^^^^):
    2: <div class="container">
    3: <div class="posts-show-item">
    4: <div class="post-user-name">
    5: <%= image_tag "#{@user.image.to_s}" %>
    6: <%= link_to(@user.name,"/users/#{@user.id}") %>
    7: <div class="posts-following-btn">
    8: <% if current_user != @user %>

    app/views/posts/show.html.erb:5
    となってしまいます。。。
  10. <%= image_tag @post.user.image %>
    ではどうでしょうか。。。
  11. @kqkky1101

    Questioner

    @Jun01tさま
    申し訳ございません、自己解決いたしました。
    今回の原因としてはpost.rbに
    def user
    return User.find_by(id: self.user_id)
    end
    を定義し、showアクションで本来@user=@post.userを定義していたのですが
    どこかで誤って消してしまっていたみたいです。
    すごくしょうもないエラーで申し訳ございませんでした。。。
    夜遅くまで対応いただきありがとうございました。。!
  12. そうですか。。。!よかったです!

usersのshow.html.erbにも同様の<%= image_tag @user.image %>を記載していますが、こちらは問題なく出力されております。

<div class="main user-show">
  <div class="container">
    <div class="user">
      <%= image_tag @user.image %>
        <h2><%= @user.name %></h2>
        <p><%= @user.email %></p>

        <%= @user.introduction %>
    </div>

    <div class=introduction>
      <% if @user.id==current_user.id %>
        <%= link_to("編集","/users/edit") %>
      <% end %>
    </div>

    <div class="users-following-btn">
      <% if current_user != @user %>
        <% if current_user.following?(@user) %>
          <%= button_to 'フォロー外す', user_relationships_path(@user.id), method: :delete %>
        <% else %>
          <%= button_to 'フォローする', user_relationships_path(@user.id), method: :POST %>
        <% end %>
      <% end %>
    </div>

    <%= link_to follows_user_path(@user) do %>
      <h6>フォロー<%= @following_users.count %></h6>
    <% end %>
    <%= link_to followers_user_path(@user) do %>
      <h6>フォロワー<%= @follower_users.count %></h6>
    <% end %>
    

    <ul class="user-tabs">
      <li class="active"><%= link_to("投稿", "/users/#{@user.id}") %></li>
      <li><%= link_to("いいね!", "/users/#{@user.id}/likes") %></li>
    </ul>


    <% @user.posts.each do |post|%>
      <div class="posts-index-item">
        <div class="post-left">
          <%= image_tag post.user.image %>
        </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 %>
  </div>
</div>
0Like

すみません。users_controller.rbとposts/show.html.erbファイルを見てみないとわかりません。

0Like

Your answer might help someone💌