Rails Micropostのお気に入り機能2
- 評価
- クリップ 0
- VIEW 1,132
前提・実現したいこと
プログラミング初心者です。どなたか教えてくださいm_ _m
Railsで既に作成しておいたTwitterクローンに作成したMicropost(投稿)をUserがお気に入りに登録できる機能を追加することにしました。(お気に入り一覧を表示するページを作成し、ナビバーから自分のお気に入り一覧ページへのリンクをつけ、users#show にそれぞれのUserのお気に入り一覧へのリンクをつける)
https://tarzanposts.herokuapp.com/
※まだ試作段階ですが、アプリのURLになります。(herokuにデプロイしたものですので、表示されるエラー画面は異なります)
①ユーザー詳細のFavoritesタブのリンクをクリックしても、お気に入り一覧ページに行けない。
②お気に入りに登録しているMicropostを削除しようとすると、エラーメッセージが表示されて削除できない。(お気に入りに登録していないMicropostは正常に削除できる)
③_navbar.html.erb で
Favoritesのhref属性を <%= likes_user_path(@user) %>
にして、ログアウトしてToppages/indexの画面を表示させようとすると、下記のエラー画面が表示されてしまう。(href属性を / にしたら、正常に表示される)
発生している問題・エラーメッセージ
NoMethodError in Users#likes
undefined method `email' for #<Favorite:0x00007f61782a2e30>
Extracted source (around line #3):
module UsersHelper
def gravatar_url(user, options = { size: 80 })
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
size = options[:size]
"https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
end
ActiveRecord::StatementInvalid in MicropostsController#destroy
Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`microposts_development`.`favorites`, CONSTRAINT `fk_rails_98783f2eed` FOREIGN KEY (`micropost_id`) REFERENCES `microposts` (`id`)): DELETE FROM `microposts` WHERE `microposts`.`id` = 2
Extracted source (around line #18):
def destroy
@micropost.destroy
flash[:success] = "メッセージを削除しました。"
redirect_back(fallback_location: root_path)
end
ActionController::UrlGenerationError in Toppages#index
No route matches {:action=>"likes", :controller=>"users", :id=>nil}, missing required keys: [:id]
Extracted source (around line #7):
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="<%= likes_user_path(@user) %>">Favorites</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
該当のソースコード
users_controller.rb
class UsersController < ApplicationController
before_action :require_user_logged_in, only: [:index, :show, :followings, :followers, :likes]
def index
@users = User.order(id: :desc).page(params[:page]).per(25)
end
def show
@user = User.find(params[:id])
@microposts = @user.microposts.order(id: :desc).page(params[:page])
counts(@user)
@favorites = @user.favorites.page(params[:page])
counts(@user)
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
flash[:success] = 'ユーザを登録しました。'
redirect_to @user
else
flash.now[:danger] = 'ユーザの登録に失敗しました。'
render :new
end
end
def followings
@user = User.find(params[:id])
@followings = @user.followings.page(params[:page])
counts(@user)
end
def followers
@user = User.find(params[:id])
@followers = @user.followers.page(params[:page])
counts(@user)
end
def likes
@user = User.find(params[:id])
@favorites = @user.favorites.page(params[:page])
counts(@user)
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
application.html.erb
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Microposts</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script defer src="https://use.fontawesome.com/releases/v5.7.2/js/all.js"></script>
</head>
<body>
<%= render 'layouts/navbar' %>
<div class="container">
<%= render 'layouts/flash_messages' %>
<%= yield %>
</div>
</body>
</html>
_navbar.html.erb
<header class="mb-4">
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<a class="navbar-brand" href="/">Microposts</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="<%= likes_user_path(@user) %>">Favorites</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarSupportedContent">
<ul class="navbar-nav">
<% if logged_in? %>
<li class="nav-item"><%= link_to 'Users', users_path, class: 'nav-link' %></li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown"><%= current_user.name %></a>
<ul class="dropdown-menu dropdown-menu-right">
<li class="dropdown-item"><%= link_to 'My profile', user_path(current_user) %></li>
<li class="dropdown-divider"></li>
<li class="dropdown-item"><%= link_to 'Logout', logout_path, method: :delete %></li>
</ul>
</li>
<% else %>
<li class="nav-item"><%= link_to 'Signup', signup_path, class: 'nav-link' %></li>
<li class="nav-item"><%= link_to 'Login', login_path, class: 'nav-link' %></li>
<% end %>
</ul>
</div>
</nav>
</header>
index.html.erb
<% if logged_in? %>
<div class="row">
<aside class="col-sm-4">
<%= form_with(model: @micropost, local: true) do |f| %>
<div class="form-group">
<%= f.text_area :content, class: 'form-control', rows: 5 %>
</div>
<%= f.submit 'Post', class: 'btn btn-primary btn-block' %>
<% end %>
</aside>
<div class="col-sm-8">
<%= render 'microposts/microposts', microposts: @microposts %>
</div>
</div>
<% else %>
<div class="center jumbotron">
<div class="text-center">
<h1>Welcome to the Microposts</h1>
<%= link_to 'Sign up now!', signup_path, class: 'btn btn-lg btn-primary' %>
</div>
</div>
<% end %>
toppages_controller.rb
class ToppagesController < ApplicationController
def index
if logged_in?
@micropost = current_user.microposts.build # form_with 用
@microposts = current_user.feed_microposts.order(id: :desc).page(params[:page])
end
end
end
likes.html.erb
<div class="row">
<aside class="col-sm-4">
<div class="card">
<div class="card-header">
<h3 class="card-title"><%= @user.name %></h3>
</div>
<div class="card-body">
<img class="rounded img-fluid" src="<%= gravatar_url(@user, { size: 500 }) %>" alt="">
</div>
</div>
<%= render 'relationships/follow_button', user: @user %>
</aside>
<div class="col-sm-8">
<ul class="nav nav-tabs nav-justified mb-3">
<li class="nav-item"><a href="<%= likes_user_path(@user) %>" class="nav-link <%= 'active' if current_page?(likes_user_path(@user)) %>">Favorites <span class="badge badge-secondary"><%= @count_favorites %></span></a></li>
<li class="nav-item"><a href="<%= user_path(@user) %>" class="nav-link <%= 'active' if current_page?(user_path(@user)) %>">Microposts <span class="badge badge-secondary"><%= @count_microposts %></span></a></li>
<li class="nav-item"><a href="<%= followings_user_path(@user) %>" class="nav-link <%= 'active' if current_page?(followings_user_path(@user)) %>">Followings <span class="badge badge-secondary"><%= @count_followings %></span></a></li>
<li class="nav-item"><a href="<%= followers_user_path(@user) %>" class="nav-link <%= 'active' if current_page?(followers_user_path(@user)) %>">Followers <span class="badge badge-secondary"><%= @count_followers %></span></a></li>
</ul>
<%= render 'users', users: @favorites %>
</div>
</div>
試したこと
①に関しては、fovoritesテーブルに"email"というカラムがないからかと思い、emailカラムを作成してみましたが、改善せず。(usersテーブルのmigrationファイル内でemailカラムの行に:null => falseをつけてみても変わりませんでした)
②に関しては、お気に入り機能を実装する前は正常に動作しており、原因分かりませんでした。
⇒microposts_controller.rbの記述等は間違いないでしょうか?
補足情報(FW/ツールのバージョンなど)
DB:MySQL
FW:Ruby on Rails5.2.2
コーディング環境:AWS Cloud9
バージョン管理システム:Git/GitHub
API用サーバー:Heroku
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
0
1の方は現時点で ??? です
2は、
Favorite が belongs_to :micropost になっています。このDB定義を見せて頂くのを忘れましたが、おそらく micropost_id が外部keyになっています。
このため favoriteが残っている状態で相手の micorpostを削除しようとするとエラーになります。
Micropost の has_many :favorites に dependent: :destroy を追加してください
ただ、、、おかしいですね。
has_many :favorites, class_name: 'User'
favorites って Favorit と関連しているのでは?
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
1に関しては...
gravatar_url の呼び出し側で第一引数に Favorite のインスタンスを渡しているのが原因かと。
実際は User インスタンスを渡すべきです。
こういうときのデバッグ方法は
undefined method 'email'
とエラーメッセージが出ているので
そのメソッドを呼び出しているオブジェクト(ここでは user
を確認してみるのが良いです。
私なら email の記述がある直前の行に以下を追加します。
p HOGE: user.class
これでログに出力される HOGE
な表示を見つけて user オブジェクトのクラスがなんなのかを確認するでしょう
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
winterboum
2020/09/06 05:52
沢山ソース載ってますが必要なものがひとつもないです。
modelの関連定義のところを載せてください。
お気に入り一覧のviewとそれを呼ぶcontrollerを載せてください
winterboum
2020/09/06 18:10
もう少しわかり易くしてください
1. 「Favoritesタブのリンクをクリック」 この「Favoritesタブのリンク」はどのcodeのどの部分ですか?
2. クリックした時に行くのは どのcodeのどのactionですか
3. そのaxctionが呼び出すview == エラーが出るview は likes.html.erb ですか?
あと、 counts(@user) というのは何をしているのでしょう
winterboum
2020/09/06 18:31
お気に入り と Micropost のモデルの関連定義も確認したい
Tarzan3154
2020/09/06 21:38
1.「Favoritesタブのリンク」は show.html.erb の <%= likes_user_path(@user) %> の部分です。
2.クリックした時に行くのは、userモデルのlikesアクションです。
3.エラーが出るviewは likes.html.erb です。
counts(@user)については、詳細画面でFavorites・Microposts・Followings・Followersに登録している数を表示する為に入れています。
winterboum
2020/09/07 06:39
う〜む、、
予想していた通りの遷移ですね、 それで @user が undefined method `email' for #<Favorite: になるのは解せない。
counts(@user)って@userを使っているだけで、代入などはしていないですよね?codeはhelper に?
質問2の原因はわかっているのですが、その確認のために「お気に入り と Micropost のモデルの関連定義も確認したい」
Tarzan3154
2020/09/08 01:05
counts(@user)については、users_controlloer.rb内で(favoritesならlikesアクションで)代入しています。
users_helper.rbのソースコードも追記していますので、ご確認お願いします。
「お気に入り と Micropost のモデルの関連定義も確認したい」
⇒「favorite.rb」と「micropost.rb」は載せておりますが、そちらのコードのことではないのでしょうか?
winterboum
2020/09/08 10:51
あ、』見落としてました
Tarzan3154
2020/09/08 18:23
質問3を追加で入れてます。
もしお時間あれば、ご回答よろしくお願い致します。
winterboum
2020/09/08 19:53
codeをそのまま書いていただかないと。
人間語に翻訳すると人によって訳し方が違うから
Tarzan3154
2020/09/08 22:03
「application.html.erb」と「_navbar.html.erb」は一応追記済みですが、
そちらを確認いただいた上での発言ですかね?
(私が言葉足らずでコードを追記した旨をコメントしていないことが原因でしたらすみません)
winterboum
2020/09/09 07:53
こーど追記は見落としてました。
で、
何行目あたりなのかがわからないと、探すのこんなんです
Tarzan3154
2020/09/09 11:06
質問しているのは、
_navbar.html.erb の 7行目 Favoritesのhref属性を <%= likes_user_path(@user) %>
にして、ログアウトしてToppages/indexの画面(およびMicropost一覧ページ)を表示させようとすると、
上記のエラー画面が表示されてしまうのですが、原因をご教示お願いできないでしょうか?(href属性を / にしたら、正常に表示される)
winterboum
2020/09/09 12:10
@user に値が入ってませんね。
蛇足
<a class="navbar-brand" href="<%= likes_user_path(@user) %>">Favorites</a>
⇓
<%= link_to "Favorites",likes_user_path(@user) , class: "navbar-brand" %>
Tarzan3154
2020/09/10 17:23
@user に値が入ってませんね。
⇒それは、users_controller.rbのindexアクションを確認すればよろしいでしょうか?
winterboum
2020/09/10 17:45
users_controller.rbのindexアクション から呼び出しているならそうです。
Toppages/indexの画面(およびMicropost一覧ページ)から呼び出しているならそちらのactionです
Tarzan3154
2020/09/14 17:19
色々調べてみましたが、原因分かりませんでした。
「index.html.erb」「toppages_controller.rb」を追記しておりますが、
修正点はありますでしょうか?
winterboum
2020/09/14 18:37
index.html.erb は どのdirのですか? それによって見るべき controllerがちがいます
Tarzan3154
2020/09/14 19:11
toppages/indexです。