@LUC_rise (甚一朗 的場)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

rails Twitterクローンにおける、お気に入り機能の動作に関して

解決したいこと

railsにてTwitterクローンアプリを制作中
お気に入り機能を実装しようとしています。ボタンを押してその投稿をお気に入りに登録する機能です。
原因かと思われるファイルを載せますのでご回答お願いいたします。

[favoriteボタンを押した後にunfavoriteボタンに変化するようにしたいです]

発生している問題・エラー

エラーメッセージは無く、アプリケーション上での表示の不具合です

該当するソースコード

user.rb

class User < ApplicationRecord
  before_save { self.email.downcase! }
  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
                    uniqueness: { case_sensitive: false }
  has_secure_password

  has_many :microposts
  has_many :relationships
  has_many :followings, through: :relationships, source: :follow
  has_many :reverses_of_relationship, class_name: 'Relationship', foreign_key: 'follow_id'
  has_many :followers, through: :reverses_of_relationship, source: :user
  
  has_many :favorites
  has_many :fav, through: :favorites, source: :micropost

  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
  
  def feed_microposts
    Micropost.where(user_id: self.following_ids + [self.id])
  end
  
  def favorite(other_micropost)
    unless self == other_micropost
      self.favorites.find_or_create_by(micropost_id: other_micropost.id)
    end
  end

  def unfavorite(other_micropost)
    favorite = self.favorites.find_by(micropost_id: other_micropost.id)
    favorite.destroy if favorite
  end

  def favorite?(other_micropost)
    self.fav.include?(other_micropost)
  end
  
end

_favorite_button.html.erb

<% if current_user.favorite?(micropost) %>
  <%= form_with(model: current_user.favorites.find_by(micropost_id: micropost.id), method: :delete) do |f| %>
    <%= hidden_field_tag :micropost_id, micropost.id %>
    <%= f.submit 'Unfavorite', class: 'btn btn-danger btn-sm' %>
  <% end %>
<% else %>
  <%= form_with(model: current_user.favorites.build) do |f| %>
    <%= hidden_field_tag :micropost_id, micropost.id %>
    <%= f.submit 'Favorite', class: 'btn btn-primary btn-sm' %>
  <% end %>
<% end %>

favorites_controller.rb

class FavoritesController < ApplicationController
  before_action :require_user_logged_in

  def create
    micropost = Micropost.find(params[:micropost_id])
    current_user.favorite(micropost)
    flash[:success] = 'お気に入りに追加しました'
    redirect_to request.referer
  end

  def destroy
    micropost = Micropost.find(params[:micropost_id])
    current_user.unfavorite(micropost)
    flash[:success] = 'お気に入りを解除しました'
    redirect_to request.referer
  end
end

自分で試したこと

恐らくuser.rbで定義したfavorite?メソッドがうまく機能していないのではないかと思い、その部分の記述を見直してみましたが皆目見当もつきません。otherを外してみたり、selfを外してみたり。
エラーメッセージが無いのでどの部分に問題があるのか見当をつける段階で躓いている状態です。。。m(__)m

0 likes

1Answer

Favoriteボタンを押下後、ページをリロードするとUnfavoriteボタンに変化していますか?そうであればCRUD操作は成功しています。

質問の意味が少し分かりにくいのですが、ボタン押下でページをリロードすることなくボタンの表示を切り替えたいという意味でよろしいでしょうか?

そうした操作を行うには、クライアント側でjavascriptを書く必要があります。
以下は参考です。実際の要件に合わせて書き変えてください。


const el = document.getElementById("favorite-btn")

el.addEventListener("click", (e) => {
  if (e.target.classList.contains("btn-danger")) {
    e.target.classList.remove("btn-danger");
    e.target.classList.add("btn-primary");
    return
  }
  // else
  e.target.classList.add("btn-danger");
  e.target.classList.remove("btn-primary");
})


0Like

Comments

  1. @LUC_rise

    Questioner

    仰る通りの認識で間違いないのですが、Javascriptを使わずに解決する方法はありますでしょうか?

    Railsのみで解決したいです。
  2. ページをリドードせずに、一部だけ更新ですよね?だとしたらないです。jsを使ってください。
  3. @LUC_rise

    Questioner

    申し訳ないです。読み間違えていました!
    ページリロードして大丈夫です。。。!
  4. ということは、

    Favoriteボタンを押下後、ページをリロードするとUnfavoriteボタンに変化していますか?そうであればCRUD操作は成功しています。

    という質問に対してはNoということですか?
  5. @LUC_rise

    Questioner

    そうですね、、、ページリロードをした後もfavoriteのままでした。
    つまりCRUD操作自体ができていないということなのでしょうか?
  6. スマホからなのでちょっと雑なレビューですが、
    Userクラスの

    unless self == other_micropost

    は正しいですか?UserインスタンスとMicropostインスタンスを比較してるように見えます。

    CRUDで失敗してるか、viewのcurrent_user.favorite?(micropost)で常にfalseになってるのか判然としませんので、binding.pryを挿入してみたり、rails consoleコマンドでそれぞれの結果をテストしてみて、どこで期待と違う結果となっているか確認してみるといいと思います。

Your answer might help someone💌