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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

4243閲覧

【Ruby on Rails】フォロー機能 undefined method `id' for nil:NilClassというエラーメッセージが出る

is02

総合スコア17

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

1クリップ

投稿2020/01/15 15:28

編集2020/01/16 09:53

前提・実現したいこと

フォロー機能をつけたい

発生している問題・エラーメッセージ

イメージ説明

該当のソースコード

relationshipsテーブル

class CreateRelationships < ActiveRecord::Migration[5.2] def change create_table :relationships do |t| t.references :user, foreign_key: true t.references :follow, foreign_key: { to_table: :users } t.timestamps t.index [:user_id, :follow_id], unique: true end end end

【Model】
relationship.rb

class Relationship < ApplicationRecord belongs_to :user belongs_to :follow, class_name: 'User' validates :user_id, presence: true validates :follow_id, presence: true end

user.rb

class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :post_images, dependent: :destroy has_many :favorites, dependent: :destroy has_many :fav_post_images, through: :favorites, source: :post_image has_many :cosplay_favorites, dependent: :destroy has_many :cosplay_fav_post_images, through: :favorites, source: :post_image has_many :post_comments, dependent: :destroy validates :name, presence: true, length: { in: 2..15 } attachment :profile_image has_many :relationships has_many :followings, through: :relationships, source: :follow has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: 'follow_id' has_many :followers, through: :reverse_of_relationships, source: :user def follow(other_user) unless self == other_user self.relationships.find_or_create_by(follow_id: other_user.id) end end def unfollow(other_user) relationship = self.relationships.find_by(follow_id: other_user.id) relationship.destroy if relationship end def following?(other_user) self.followings.include?(other_user) end end

post_image.rb

class PostImage < ApplicationRecord belongs_to :user has_many :favorites, dependent: :destroy has_many :fav_users, through: :favorites, source: :user has_many :cosplay_favorites, dependent: :destroy has_many :cosplay_fav_users, through: :cosplay_favorites, source: :user has_many :post_comments, dependent: :destroy attachment :real_image attachment :cosplay_image default_scope -> { order(created_at: :asc) } end

【Controller】
relationship_controller.rb

class RelationshipsController < ApplicationController before_action :set_user def create user = User.find(params[:relationship][:follow_id]) following = current_user.follow(user) if following.save flash[:success] = 'ユーザーをフォローしました' redirect_to user else flash.now[:alert] = 'ユーザーのフォローに失敗しました' redirect_to user end end def destroy user = User.find(params[:relationship][:follow_id]) following = current_user.unfollow(user) if following.destroy flash[:success] = 'ユーザーのフォローを解除しました' redirect_to user else flash.now[:alert] = 'ユーザーのフォロー解除に失敗しました' redirect_to user end end private def set_user user = User.find(params[:relationship][:follow_id]) end end

postimages_controller.rb

class PostImagesController < ApplicationController def new @post_image = PostImage.new end def create @post_image = PostImage.new(post_image_params) @post_image.user_id = current_user.id @post_image.save redirect_to post_images_path end def index @post_images = PostImage.page(params[:page]).reverse_order @post_image = PostImage.new @user = @post_image.user end def show @post_image = PostImage.find(params[:id]) @post_comment = PostComment.new end def destroy @post_image = PostImage.find(params[:id]) @post_image.destroy redirect_to post_images_path end private def post_image_params params.require(:post_image).permit(:real_image_name, :cosplay_image_name, :real_image, :cosplay_image, :caption, :favorites_count) end end

users_controller.rb

class UsersController < ApplicationController def show @user = User.find(params[:id]) @post_images = @user.post_images.page(params[:page]).reverse_order end def edit @user = User.find(params[:id]) end def update @user = User.find(params[:id]) @user.update(user_params) redirect_to user_path(@user.id) end private def user_params params.requrie(:user).permit(:name, :profile_image) end end

【部分テンプレート】
relationships/_follow_button.html.erb

<% unless current_user == user %> <% if current_user.following?(user) %> <%= form_for(current_user.relationships.find_by(follow_id: user.id), html: { method: :delete }) do |f| %> <%= hidden_field_tag :follow_id, user.id %> <%= f.submit 'Unfollow', class: 'btn btn-danger btn-block' %> <% end %> <% else %> <%= form_for(current_user.relationships.build) do |f| %> <%= hidden_field_tag :follow_id, user.id %> <%= f.submit 'Follow', class: 'btn btn-primary btn-block' %> <% end %> <% end %> <% end %>

【View】
index.html.erb

<div class="header"> <nav class="navigation"> <img src="/assets/logo.png"> <ul> <li> <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> </li> <li> <%= link_to '投稿する', new_post_image_path %> </li> <li> <%= link_to 'マイページ', user_path(current_user.id) %> </li> </ul> </nav> </div> <div class="post_images_index_wrapper"> <% @post_images.each do |post_image| %> <div class="index_box"> <div class="post_images_index_user"> <ul> <li> <%= link_to user_path(post_image.id) do %> <%= attachment_image_tag @user, :profile_image, fallback: "no_image.jpg" %> <% end %> </li> <li> <p><%= link_to "#{post_image.user.name}", user_path(post_image.id) %></p> </li> <li> <%= render 'relationships/follow_button', user: @user %> </li> </ul> </div> <div class="post_images_index_title"> <div class="image_title"> <h2>Real</h2> </div> <div class="image_title"> <h2>Cosplay</h2> </div> </div> <div class="post_images_box"> <div class="post_image"> <%= attachment_image_tag post_image, :real_image %> </div> <div class="post_image"> <%= attachment_image_tag post_image, :cosplay_image %> </div> </div> <div class="image_name"> <%= post_image.real_image_name %> </div> <div class="image_name"> <%= post_image.cosplay_image_name %> </div> <div class="favorites_area"> <div class="favorite_area"> <%= render partial: 'post_images/post_images', locals: { post_image: post_image } %> </div> <div class="favorite_area"> <%= render partial: 'post_images/cosplay_post_images', locals: { post_image: post_image } %> </div> </div> <div class="image_caption"> <ul> <li> <%= link_to user_path(post_image.id) do %> <%= attachment_image_tag @user, :profile_image, fallback: "no_image.jpg" %> <% end %> </li> <li> <p><%= link_to "#{post_image.user.name}", user_path(post_image.id) %> </p> </li> <li> <p><%= link_to "#{post_image.post_comments.count}件のコメント", post_image_path(post_image.id) %></p> </li> </ul> <span class="caption"><%= post_image.caption %></span> </div> </div> <% end %> <%= paginate @post_images, class: "pagenate" %> </div>

【ルーティング】
routes.rb

Rails.application.routes.draw do devise_for :users root 'post_images#index' resources :post_images, only: [:new, :create, :index, :show, :destroy] do resource :post_comments, only: [:create, :destroy] end resources :users, only: [:show, :edit] post '/favorite/:id' => 'favorites#favorite', as: 'favorite' post '/cosplay_favorite/:id' => 'cosplay_favorites#favorite', as: 'cosplay_favorite' resources :relationships, only: [:create, :destroy] # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end

補足情報(FW/ツールのバージョンなど)

ruby 2.5.7p206
Rails 5.2.4.1

よろしくお願いいたします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

winterboum

2020/01/15 20:45

index.htmlを呼び出しているcontrollerも載せてください
is02

2020/01/15 23:26

申し訳ありません、追記致しました。
guest

回答1

0

ベストアンサー

def index では @post_images しか定義していないのに
index.html で
<%= render 'relationships/follow_button', user: @user %>
@user を使っています。
このため partialで使われる user がnilとなっています。

def indexで @userを定義してください

投稿2020/01/15 23:49

winterboum

総合スコア23567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

is02

2020/01/16 01:05

ご回答ありがとうございます。 @userを定義する際に、post_images_controllerでusers_idを持ってくる方法はありますでしょうか? userモデルとpost_imageモデルはUser 1:Post_Image Nの関係で関連付けしているのですが、 @user = PostImage.find(params[:id])としても、undefined method `users'というエラーが表示されます。
winterboum

2020/01/16 02:36

PostImage のソースがないので、判断できませんが、関連付けがきちんとできているなら、 @user = post_image.user です
is02

2020/01/16 04:37

post_image.rbを追記致しました。 @user = PostImage.userとすると「undefined method `user'」と出てしまいます。 これは関連付けがされていないということなんでしょうか?
winterboum

2020/01/16 04:50

あ、ごめん @user = post_image.user の post_image は @post_image = PostImage.new の @post_image のつもりでした
is02

2020/01/16 08:41

@user = @post_image.userと記入したのですが、 「undefined method `user' for nil:NilClass」と出てしまいます。 色々調べたんですが、解決方法が分かりません。 post_images_controllerで@post_imageという変数を複数のアクションで使っているのですが、それも関係しているのでしょうか。 アドバイスを頂けると幸いです。
is02

2020/01/16 08:50

また、indexアクション内に @user = @post_image.userと、@post_image = PostImage.newを記入すると 「undefined method `user' for nil:NilClass」は出ないんですが、 relationships/_follow_button.html.erb内の、 <%= hidden_field_tag :follow_id, user.id %>の行で 「undefined method `id' for nil:NilClass」と出ます。
is02

2020/01/16 09:12

teratailの過去質問を拝見致しました。 <%= hidden_field_tag :follow_id, user.id %>でエラーが出るのは、 params[:relationship][:follow_id]のparams[:relationship] がパラメータで送られてきていないのが原因とご回答されていました。 そのため、 <%= hidden_field_tag :follow_id, user.id %>を <%= f.hidden_field :follow_id, user.id %>に変更しました。 また、 relationships_controller内で、userは@をつけないと実際のActionでは使えないとのことでしたので、変更致しました。
is02

2020/01/16 09:18 編集

↑の内容の続きですが、 「undefined method `id' for nil:NilClass」が _follow_button.html.erb内の <%= f.hidden_field :follow_id, user.id %>でエラーが発生してしまいます。 また、before_action :set_userをindexなどparamsがこないactionでも呼ばれてしまわないように、 before_action :set_user only: [:create, :destroy]と変更しましたが、現状エラーが発生したままです。
winterboum

2020/01/16 09:20

問題を整理しなおしましょう。 どういう操作をすると、どういう現象になるのか、 と 載せてあるプログラムをその時のものにしてください
is02

2020/01/16 09:34

申し訳ございません。 まずpost_images_controllerのindexアクション内、 @user = PostImage.userを@user = @post_image.userに変更したところ、 「undefined method `user' for nil:NilClass」というエラーが発生します。
winterboum

2020/01/16 09:37

@post_image が未定義ですね。 そのuserはどのpost_imageのuserなんでしょう
is02

2020/01/16 09:55

@post_imageを定義致しました。すみません、理解できておりません。。。
is02

2020/01/16 10:31

@post_imageを定義すると、 relationships/_follow_button.html.erb内の <%= hidden_field_tag :follow_id, user.id %>に対して 「undefined method `id' for nil:NilClass」と表示されます。
winterboum

2020/01/16 10:56

index.htmlをきちんと見ていなかったのですが今回見なおして問題がわかりました。 が、その前に @post_image = PostImage.new ではuser情報が与えられていないので @user = @post_image.user はnilになります。 問題は、indexで @userを使っていることです。 「@userがnilになってる」という視点で今までコメントしてきちゃってましたが、@userそのものがいかんです。 <% @post_images.each do |post_image| %> の中にuserは何回か出てきています <%= attachment_image_tag @user, :profile_image, fallback: "no_image.jpg" %> <%= link_to "#{post_image.user.name}", user_path(post_image.id) %> <%= render 'relationships/follow_button', user: @user %> これらの中の post_image.user の userが正解です。 @userが出てきていますが、@userってある特定のuserということですから、indexの様な複数 を扱う中では出てくるのがおかしいのですが、なにか意味の有るuserなのかと思っていました。 indexのなかの @user は意図としては @post_images.each do |post_image| のpost_imageのuserでは? ならば @userは post_image.user に修正してください
winterboum

2020/01/16 10:58

「@userってある特定のuserということですから」 @userそのものにはそいういう意味はないです。そういう意味で大抵使われている かな
is02

2020/01/16 13:13

ありがとうございます!無事解決致しました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問