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

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

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

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

Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby

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

Ruby on Rails

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

Q&A

解決済

2回答

1123閲覧

[フォロー機能実装] Viewにおけるform_for使用時の undefined method エラーの解決法について

SELA

総合スコア13

Ruby on Rails 5

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

Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby

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

Ruby on Rails

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

0グッド

1クリップ

投稿2019/06/29 03:48

初学者の者で、現在Qiitaの下記の記事を参考にさせて頂きながらフォロー機能の実装を試みております。
Qiita:railsでフォロー機能をつける。

下記のようなエラーが生じて解決法が見出せていないために、今回ご質問させていただきます。
以下、詳細を記述いたします。

環境

ruby 2.5.3
rails 5.2.3


###事象
特定userの詳細ページにて「フォローする」ボタンを表示させようとして当該ページ(http://localhost:3000/users/2)にアクセスしたところ、下記のエラーが発生しました。

error

1undefined method `relationships_path' for #<#<Class:0x00007fa354d636a8>:0x00007fa354d61c18>
  • 対象のViewファイル

現在のログインユーザーであるcurrent_user(Gem deviseにより定義)について、後述のfollowing_relationshipsのテーブルを生成しようとしています。

erb

1<%= form_for current_user.following_relationships.new(following_id: @user.id) do |f| %> 2 <div><%= f.hidden_field :following_id %></div> 3 <%= f.submit "フォローする", class: "btn btn-sm btn-primary follow-btn" %> 4<% end %>
  • Model

上記内でのメソッドfollowing_relationshipsの定義元はUserモデル(app/models/user.rb)内にあります。
以下、フォロー機能周りの記述の抜粋

ruby

1class User < ApplicationRecord 2 3 has_many :following_relationships, foreign_key: "follower_id", 4 class_name: "Relationship", dependent: :destroy 5 6 has_many :followings, through: :following_relationships 7 8 has_many :follower_relationships, foreign_key: "following_id", 9 class_name: "Relationship", dependent: :destroy 10 11 has_many :followers, through: :follower_relationships 12 13 # ユーザー登録機能はGem deviseを使用 14 devise :database_authenticatable, :registerable, 15 :recoverable, :rememberable,:trackable, :validatable 16 17 def following?(other_user) 18 following_relationships.find_by(following_id: other_user.id) 19 end 20 21 # 次行のfollow!は後述のCreateアクション内で使用 22 def follow!(other_user) 23 following_relationships.create!(following_id: other_user.id) 24 end 25 26 def unfollow?(other_user) 27 following_relationships.find_by(following_id: other_user.id).destroy 28 end 29end 30

Userモデルに依存するRelationshipモデルは下記であり、モデル間の関連付けやカラムの整合は取れているように思います。

ruby

1class Relationship < ApplicationRecord 2 belongs_to :follower, class_name: "User" 3 belongs_to :following, class_name: "User" 4 validates :follower_id, presence: true 5 validates :following_id, presence: true 6end

また、relationshipsテーブルの構成は、db/schema.rbより

ruby

1 create_table "relationships", force: :cascade do |t| 2 t.integer "follower_id" 3 t.integer "following_id" 4 t.datetime "created_at", null: false 5 t.datetime "updated_at", null: false 6 t.index ["follower_id", "following_id"], name: "index_relationships_on_follower_id_and_following_id", unique: true 7 t.index ["follower_id"], name: "index_relationships_on_follower_id" 8 t.index ["following_id"], name: "index_relationships_on_following_id" 9 end
  • Controller

以下は、狙いのcreateアクションについての記述です。

ruby

1class RelationshipsController < ApplicationController 2 def create 3 @user = User.find(params[:relationship][:following_id]) 4 current_user.follow!(@user) 5 if following_relationships.save 6 flash[:notice] = "フォローしました!" 7 redirect_back(fallback_location: root_path) 8 else 9 flash[:notice] = "フォローに失敗しました。" 10 redirect_back(fallback_location: root_path) 11 end 12 end 13end 14
  • Routing

routes.rbのRelationshipsについての記述部分です。

ruby

1Rails.application.routes.draw do 2 3 resources :users do 4 member do 5 get :following, :followers 6 end 7 resources :relationships, only: [:create, :destroy] 8 end 9 10end

上記によりPATHは以下のとおり生成されています。

following_user GET /users/:id/following(.:format) users#following followers_user GET /users/:id/followers(.:format) users#followers user_relationships POST /users/:user_id/relationships(.:format) relationships#create user_relationship DELETE /users/:user_id/relationships/:id(.:format) relationships#destroy

 以上から、Viewから関係性を遡っていき、following_relationshipsメソッドに紐づく各モデル間の関連付けやカラムの整合、ルーティングの生成は出来ているように思います。
静的コード解析ツールのrubocopでもチェックしましたが、全角文字混入の指摘なども確認されなかったので、なぜパスが通らずにうまくいかないのか頭を悩ませております。

根本的な基礎事項の理解が至らずに生じた些細なエラーなのかもしれませんが、form_forの使用法や、既存の質疑などの情報を参照しても解決法が見つかっていないために、ここでご相談させて頂きます。
お手数をお掛けいたしますが、ご助言やご指摘のほど宜しくお願い申し上げます。

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

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

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

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

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

guest

回答2

0

ベストアンサー

relationships_pathではなくuser_relationships_pathにフォームを送信するには

erb

1<%= form_for [親モデル, 子モデル] do |f| %>

でフォームを作成しましょう。

投稿2019/06/29 04:33

編集2019/06/29 04:34
Mugheart

総合スコア2342

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

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

SELA

2019/06/30 04:37

早々にご回答頂きありがとうございました。 form_forの基本的な使用法を理解出来ておりませんでした。 ご教示頂いた記法でコードを修正して機能の実装に成功することが出来ました。 重ねてお礼申し上げます。
guest

0

Mugheartさんにご教示頂いた記法に基づいてViewファイルのコードを修正しました。
一連の下記コードにより、ローカルホスト及びHerokuサーバー上においてフォロー/解除機能が正常に動作することを確認致しました。
また、MVC各部のメソッドや変数の定義については再考して変更を加えており、参考先記事の内容とは異なる部分があるので、以下のコードを参考にされる方はその点にご留意ください。
(ご参考までに、本質問で触れなかったdestroyアクションについても合わせて記載しておきます。)

VIEW

erb

1<!– フォローボタン > 2<%= form_for [current_user, @user.following_relationships.new(following_id: @user.id)] do |f| %> 3 <div><%= f.hidden_field :following_id %></div> 4 <%= f.submit "フォローする", class: "btn btn-sm btn-primary" %> 5<% end %>

erb

1<!– フォロー解除ボタン > 2<%= form_for [current_user, current_user.following_relationships.find_by(following_id: @user.id)], html: { method: :delete } do |f| %> 3 <%= f.submit "フォローを解除する", class: "btn btn-sm btn-secondary" %> 4<% end %>

MODEL

ruby

1class User < ApplicationRecord 2 3 # 関係部分抜粋(関連付けは変更なし) 4 has_many :following_relationships, foreign_key: "follower_id", 5 class_name: "Relationship", dependent: :destroy 6 has_many :followings, through: :following_relationships 7 has_many :follower_relationships, foreign_key: "following_id", 8 class_name: "Relationship", dependent: :destroy 9 has_many :followers, through: :follower_relationships 10 11 def following?(other_user) 12 following_relationships.find_by(following_id: other_user.id) 13 end 14 15 def follow!(other_user) 16 following_relationships.create!(following_id: other_user.id) 17 end 18 19 def unfollow!(other_user) 20 following_relationships.find_by(follower_id: other_user.id) 21 end 22 23end 24

ruby

1class Relationship < ApplicationRecord 2 # 質問投稿時より変更なし 3 belongs_to :follower, class_name: "User" 4 belongs_to :following, class_name: "User" 5 validates :follower_id, presence: true 6 validates :following_id, presence: true 7end

CONTROLLER

ruby

1class RelationshipsController < ApplicationController 2 def create 3 @user = User.find(params[:relationship][:following_id]) 4 @relationship = current_user.follow!(@user) 5 @relationship.save 6 if @relationship.save 7 flash[:notice] = @user.username += "さんをフォローしました!" 8 redirect_back(fallback_location: root_path) 9 else 10 flash[:notice] = @user.username += "さんのフォローに失敗しました。" 11 redirect_back(fallback_location: root_path) 12 end 13 end 14 15 def destroy 16 @user = Relationship.find(params[:id]).follower 17 followed = Relationship.find(params[:id]).following 18 @relationship = current_user.unfollow!(@user) 19 @relationship.destroy 20 if @relationship.destroy 21 flash[:notice] = followed.username += "さんのフォローを解除しました。" 22 redirect_back(fallback_location: root_path) 23 else 24 flash[:notice] = followed.username += "さんのフォローの解除に失敗しました。" 25 redirect_back(fallback_location: root_path) 26 end 27 end 28end

投稿2019/06/30 04:37

編集2019/06/30 04:51
SELA

総合スコア13

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問