@Tarzan3154

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Rails Micropostのお気に入り機能

はじめに

ありがちですが、RailsでTwitterクローンを作成中で、下記の通り記述してみましたが、いくつか正常に動作しない点がありますので、どなたかご教示をお願いします。

自己紹介

作者は今年の3月末ごろから独学でプログラミングを学習しています。
1年ほど前にほんの少しHTMLを触ったことがある程度で、前提知識はありませんでした。
現在はアプリを作成しながら、エンジニアへの転職を目指して勉強しています。
https://tarzanposts.herokuapp.com/
※まだ試作段階ですが、アプリのURLになります。

質問事項

既に作成しておいたTwitterクローンに作成したMicropost(投稿)をUserがお気に入りに登録できる機能を追加することにしました。(お気に入り一覧を表示するページを作成し、ナビバーから自分のお気に入り一覧ページへのリンクをつけ、users#show にそれぞれのUserのお気に入り一覧へのリンクをつける)

①自分の投稿のお気に入りボタンを押しても表示が変わらない。

_micropost.html.erb.png
users#showにてmicropost.html.erbが表示されるようパーシャルを設定しており、その中でFavoriteを押すとお気に入りには登録されるが、Unfavoriteに表示が変わらない。(favorites/favorite_buttonをパーシャルに設定しようとしても、エラーが出てうまくいきませんでした)
_favorites_button.html.erb.png

②ユーザー詳細のFavoritesタブのリンクをクリックしても、お気に入り一覧ページに行けない。

エラー画面1.png
上記のエラー画面が表示されてしまい、それぞれのUserのお気に入り一覧へ行けない。
(users_controllerの記述等は合っている?)
favorites.html.erb.png
users_controller.erb
users_controller.erb.png
users_controller.erb2.png

③ナビゲーションバーのFavoritesボタンをクリックしても、自分のお気に入り一覧ページへ遷移しない。

_navbar.html.erb.png
Favoritesのhref属性は"likes_user_path"ではない?
エラー画面2.png

④ユーザー詳細のDeleteボタンをクリックしても、

エラー画面(heroku).png
の画面が表示され、削除できない。(お気に入り機能を追加する前は削除できていた。favoriteの実装がうまくいけば直るかも?)

開発環境等

言語:Ruby
DB:MySQL
FW:Ruby on Rails
コーディング環境:AWS Cloud9
バージョン管理システム:Git/GitHub
API用サーバー:Heroku

最後に

長文になってしまいましたが、独学でやっており、自分で調べてみても行き詰ってしまい、困っています。どんな些細なことでもヒントをご教示いただけますとありがたいです。
何卒よろしくお願い致します。

0 likes

Favoritesのhref属性は"likes_user_path"ではない?

erb ファイルは,<%=... %>のような記載をしないと,
そのまま HTML のように扱われます.

ですので,現状ではリンク先は文字列 likes_user_path であるのがブラウザから確認できると思います.

例えば,

<%= link_to 'Users', users_path ...

のように記載されている部分をブラウザから確認すると,href の値は users_path ではなく,/users のように別の値になっているかと思います.

この辺りを確認するとよいかと思いました.

1Like

①自分の投稿のお気に入りボタンを押しても表示が変わらない。

favorites/favorite_buttonパーシャルを使えば、解決できそうな気がします。
パーシャル使用時にどんなエラーが出てますか?

あと、これはパーシャルの参考になればと、https://qiita.com/ITmanbow/items/1e826f2a4c0244ac3543

0Like

@atm-snag

ご回答ありがとうございます。
hrefを「<%= likes_user_path(@user) %>」に修正後、②のエラー画面と同様の表示が出るようになりました。(ご指摘の点はおそらく正しかったと思います)
②のエラー画面が表示される場合はどのようなことが考えられますか?

0Like

@ohakutsu

ご回答ありがとうございます。
パーシャル使用時のエラー.png
favorites/favorite_buttonパーシャル使用時には_micropost.html.erb上で、上記のエラー画面が表示されてしまいます。_favorites_button.html.erb上で何かコーディングミスがありますでしょうか?

0Like

@Tarzan3154
おそらくなのですが、パーシャルを使う際に、変数micropostをパーシャルに渡していないためだと思われます。
パーシャルに変数を渡したいときは、

<%= render partial: "form", locals: { thing: @thing } %>

のようにlocalsに記述する必要があります。
なお、partial, localsは省略ができるようなので、

_microposts.html.erb
<ul class="list-unstyled" >
  <% microposts.each do |micropost| %>
    <li class="media mb-3">
      <img class="mr-2 rounded" src="<%= gravatar_url(micropost.user, { size: 50 }) %>" alt="" />
    </li>
    <div>
      <%= link_to micropost.user.name, user_path(micropost.user) %>
      <span class="text-muted">posted at <%= micropost.created_at %></span>
    </div>
    <div>
      <p><%= micropost.content %></p>
    </div>
    <div>
      <% if current_user == micropost.user %>
        <%= link_to "Delete", micropost, method: :delete, data: { confirm: "You sure?" }, class: "btn btn-danger btn-sm" %>
      <% end %>
-      <%= link_to "Favorite", favorites_path(micropost_id: micropost_id), method: :post, class: "btn btn-primary btn-sm" %>
+      <%= render "favorites/favorite_button", micropost: micropost %>
    </div>
  <% end %>
</ul>

のようにするとうまくいくのかなと思います。

ちなみに、パーシャルについては、先程も取り上げましたが、部分テンプレートでスッキリ!! ❏Rails❏ - Qiitaの記事が参考になります。

0Like
ActionController::UnknownFormat in <コントローラ名>#<アクション名>

<コントローラ名>#<アクション名> is missing template ...

のエラーの場合は,メッセージとしては コントローラのアクションに対する template がありません
と言っているようです.

default では app/views/コントローラ名/アクション名.html.erb にtemplate ファイルがあることを期待されています.
UsersController#likesの場合は,apps/views/users/likes.html.erbを確認すると良いかもしれません.

リンク元ではなくて,リンク先(likes_user_path) 側の動作を確認すると良いかと思います.

ご参考

0Like

@ohakutsu

ご回答ありがとうございます。
ご指摘の点、修正したところ、トップページおよび詳細画面で「NameError」が表示されます。(詳細画面では「NameError in Users#show」)
エラー画面3.png
他に修正事項はありますでしょうか?

0Like

NameError in Toppages#index
Showing xxxx/app/views/favorites/_favorite_button.html.erb where line #8 raised.
undefined local variable or method user for xxx

とあるので,favorites/favorite_button 側で user というローカル変数かメソッドが無いようです.

favorites/favorite_button の呼び出し元で,
変数 micropost は渡しているけど,変数 user は渡していないのが原因なんじゃないかと予想します.

0Like

@atm-snag

返信遅くなりすみません。
favorites/favorite_button の呼び出し元で変数userを渡すよう修正してみましたが、改善しませんでした。
user.rb.png
user.rb2.png
user.rbの記述等は間違いないでしょうか?

0Like

エラーを見てないのでなんとも言いにくいのですが,
改善しないということが,エラーが変更にならないということでしたら.
user 変数が届いていれば,上記指摘したエラーが変更されているように思います.

又,Userモデル(#favoites?)についてですが,
ソースを簡単に眺めてみた感じだとおかしな記述ではないように見えました.

favorite_button パーシャルを見てみたのですが,

micropost_id: user.id

になっているので,この辺りはおかしいのではないか.と思っています.
micropost_idmicropostid なのでそちらが正しいのではないかと思っています.

1Like

@atm-snag @atm-snag

ご回答ありがとうございます。
少し話は逸れるのですが、詳細画面(もしくはナビバー)のFavoritesボタンを押すと、登録したお気に入りの一覧ではなく、下記のエラー画面が表示されます。
favorite一覧のエラー画面.png
Users#likesが定義されていないエラーかと思いましたが、
users_controller.erb(likes).png
上記のcontrollerの記述は間違っておりますでしょうか?

0Like

エラーとしては

/app/view/users/_users.html.erb where line #1 raised:

undefined method `any?` for nil:NilClass

簡単に訳すと,

/app/view/users/_users.html.erb の1行目で起きています.

値 `nil` : クラス(NilClass) には,`any?` というメソッドが未定義です.

となります.

場所としては if users.any? の行なので,usersnil の状態であることが予想されます.
そのために,nil.any?と解釈されて,nilには any?メソッドが無いというエラーになっていると推測します.
users/users パーシャルの中に,usersが渡されていない状態ではないかと推測します.

UsersController#likes の定義ですが

users_controller.rb
class UsersController
  def likes
    @user = User.find(params[:id])
    @favolites = @user.favorites.page(params[:page])
    counts(@user)
  end
end

特に問題はないように感じました.
counts メソッドの定義は見てないのでわからないです.

0Like

@atm-snag
ご回答ありがとうございます。
ご指摘いただいた点を修正したところ、ページが表示されるようになりました。ありがとうございます。

続けて質問ですが、Micropostを作成し、「Favorite」ボタンを押してお気に入りに登録しようとすると、
favoriteエラー.png
の画面が表示され、登録ができません。(既にお気に入り登録済みのMicropostで「Unfavorite」を押した場合も同様で、お気に入り解除もできず)
お気に入り(もしくは削除)対象のidが見つからないため発生しているエラーかと思いましたが、routes.rbおよびfavorites_controller.rbの記述は間違いないでしょうか?
routes.rb.png
favorites_controller.erb.png

0Like

リクエストパラメータの micropost_id が空文字になっています。
image.png

routes.rb や favorites_controller.rb ではなく、 view側で micropost_id のパラメータを設定している箇所が怪しそうです :eyes:

0Like

Micropost#find のエラー

Couldn't find Micropost with `id`=

となっているので,id = のid と比較している部分が空になっているため,Micropost が find (発見) できていないようです.(id=100のように,探すための値が入っていれば,エラーにそう表示される筈)
ソース的には Micropost.find(params[:micropost_id]) なので,params[:micropost_id]が怪しいです.
parameters を見ると,"micropost_id" => "" となっているので,空文字列("")がわたってきているようです.

routes と controller

上記のように,FavoritesController#create では micropost_id が渡されてきていないようです.
コントローラには,おそらく view からリクエスト(input や submit などを使って)しているので,
view の micropost_id を input している部分が怪しいと思っています.

過去の favoite_button パーシャルを見ると,<%= hidden_field_tag :micropost_id, user.id %> になっています.
この辺りで値が渡されているか確認すると良いかと思います.

_favorite_button.html.erb(質問時のもの)
<%= form_with(model: current_user.favorites.build, local: true) do |f| %>
  <%= hidden_field_tag :micropost_id, user.id %>
  <%= f.submit 'Favoite', class: 'btn btn-primary btn-block' %>
<% end %>
0Like

@atm-snag
追加でお聞きしたいのですが、ログイン後、詳細画面の「Favorites」タブ(もしくはナビバーのFavoritesタブ)をクリックしても、お気に入り一覧のページに行けず、下記のエラー画面が表示されてしまいます。(お気に入りに登録している投稿が0の場合のみ正常に表示される)
お気に入り一覧時のエラー画面.png
fovoritesテーブルに"email"というカラムがないからかと思い、emailカラムを作成してみましたが、改善せず。(usersテーブルのmigrationファイル内でemailカラムの行に:null => falseをつけてみても変わりませんでした)
こちらのエラーの原因をご教示お願いできないでしょうか?
よろしくお願い致します。

0Like

@atm-snag
ナビバー.png

追加で情報ですが、 _navbar.html.erb で 
Favoritesのhref属性を <%= likes_user_path(@user) %>
にして、ログアウトしてToppages/indexの画面を表示させようとすると、下記のエラー画面が表示されてしまいます。(href属性を / にしたら、正常に表示される)
トップページエラー画面.png
現時点では???です。
aplication.html.erbの記述等は間違いないでしょうか?
application.html.erb.png

0Like

NoMethodError in Users#likes について

この件ですが

undefined method `email` for #<Favorite:xxxx>

直訳ですと,「Favorite クラスのオブジェクトには,emailメソッドが未定義です」となります.
Favorite クラスに存在しないという推論は正しいと思います.

しかし,下記エラー部分を見ると,

エラー部分
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)

user.email と書いてあり,変数名 useremail メソッドを呼んでいます.
この user には Favorite クラスのオブジェクトではなく,User クラスのオブジェクトが入るのが正しいように思います.

ですので,gravatar_urlメソッドに渡している値が,Userクラスのオブジェクトかどうかを確認すると良さそうです.

0Like

ActionController::UrlGenerationError in Toppages#index について

エラーの行は,

<a class="navbar-brand" href="<%= likes_user_path(@user) %>">Favorites</a>

となっていて,おそらく likes_user_path(@user) で問題があります.
(それ以外は Ruby の処理ではないので,エラーの要因にならなそう)

likes_user_path() は,routes.rb を参照すると.

routes.rb
resources :users, only: [:index, :show, :new, :create] do
  member do
    get :likes
  end
end

とあるので,
likes_user_path(user)/users/#{user.id}/likes(controller = users / action = likes / id = user.id と同じ) を返すように設定されています.
(この辺り,routes を調べてもらうといいと思います.)

ここで,エラーメッセージを見ると

No route matches {:action=>"likes", :controller=>"users", :id=>nil}, missing required keys: [:id]

となっていて,上記の id = user.id の部分が,nil になっていることがわかります.

とすると,最初の likes_user_path(@user) で考えると,
@usernil になっているか,@user.idnil になっていると推測されます.

ここで,@user がどうやって設定されているかを確認します.
一般的には,変数はコントローラ方面で設定されているので,コントローラを確認します.
(=> Toppage#index メソッド内)
という流れで確認すると良いと思います.

参考

0Like

@atm-snag
ご回答ありがとうございます。

gravatar_urlメソッドに渡している値が,Userクラスのオブジェクトかどうかを確認すると良さそうです.
⇒それは、どのファイルのどの部分を確認すればよろしいでしょうか?

0Like

おそらく,どこかの URL にアクセスしたときに,view が呼ばれて,
その中で,gravater_urlメソッドが呼ばれていると思います.
その関数の呼び出しているところの変数がどうなっているか,を確認すると良いと思っています.

関数を呼び出している,view で Ruby の変数の確認をするには,

<%= user %>

のようにしてみるのはどうでしょうか?(user は変数名)
そうすると,同じURL にアクセスしたときにブラウザで表示される HTML のソースコードの中に変数の内容が出力されていると思います.

更に詳しく知りたい場合は,

<%= user.email %>

などのように,特定のプロパティを参照することもできます.

<%= user %> したときに,#<User:0xxxxxxxxx〜 みたいな文字列が出れば,
userUser クラスのinstance だと推測できます.

又,参考にも載せておきましたが,以下の方法を使ってもいいかもしれません.

<%= debug user %>
<%= simple_format user.to_yaml %>
<%= user.inspect %>

参考

1Like

@atm-snag

回答遅くなりすみません。
NoMethodError in Users#likesについて、
デバッグしてみたところ、@userに値が入っていないのかと思うのですが、
toppages_controller.rbおよびtoppages/indexにて、@userの値を加えればよろしいでしょうか?
toppages_controller.rb.png
index.html.erb.png

0Like

過去の情報をまとめると,以下でした

  • likes_user_path(@user) は,_navbar.html.erb というファイルにある
  • TopPages#index をリクエストして,上記の場所でエラーになった
    • (予想) toppages/index.html.erb の内部で,navbar をrender している
  • TopPages#index の内容は,コレ

で,

toppages_controller.rbおよびtoppages/indexにて、@userの値を加えればよろしいでしょうか?

Toppages#indexの内容から見ると,@user は足りなそうです.
それはそうなんですが,Favorite させたいユーザって誰なんでしょうか?

UI を見てないのでわからないのですが,例えばそれが micropost をした user のことだったら,
対象の micropost から user を得るのが正しいと思います.

なので,Toppages#index 内で @user を与えることが直接正解ではないかもしれません.
Toppages#indexlikes_user_path に与えるユーザって決められそうでしょうか?

0Like

Your answer might help someone💌