仅允许用户为每部电影创建一个评论

时间:2015-09-26 13:54:04

标签: ruby-on-rails activerecord devise rails-activerecord

我有我的应用设置,用户可以在其中为电影撰写评论。我想做的是限制用户每部电影只创建一个评论。我已经设法在我的评论控制器中实现了这一点:

class ReviewsController < ApplicationController
  before_action :has_reviewed, only [:new]
  ....
  def has_reviewed?
    if Review.where(user_id: current_user.id, movie_id: @movie.id).any?
      redirect_to movie_reviews_path

      flash[:notice] = "You've already written a review for this movie."
    end
  end
end

我现在遇到麻烦的地方是将这个相同的逻辑转换为我的索引视图模板,并使用Devise和CanCanCan的帮助方法。

<% if user_signed_in? && ... %> # current_user has already created a review for this movie
  <%= link_to "Edit Review", edit_movie_review_path(@movie, review) %>
<% else %>
  <%= link_to "Write a Review", new_movie_review_path %>
<% end %>

另外:有没有办法改进我的 has_reviewed?方法中的查找?我觉得有更好的方式来编写它,但无法确定最合适的修复方法。

4 个答案:

答案 0 :(得分:2)

Why not use a validation

(case x
  ((3) (displayln "x is 3"))
  ((4) (displayln "x is 4"))
  ((5) (displayln "x is 5"))
  (else (displayln "none of the above")))

这是考虑您的#app/models/review.rb class Review < ActiveRecord::Base validates :movie_id, uniqueness: { scope: :user_id, message: "You've reviewed this movie!" } end 型号review

您还可以使用ActiveRecord回调:

belongs_to :movie
  

有没有办法改善我的has_reviewed中的查找?方法

#app/models/review.rb
class Review < ActiveRecord::Base
   before_create :has_review?
   belongs_to :user, inverse_of: :reviews
   belongs_to :movie

   def has_review?
      return if Review.exists?(user: user, movie_id: movie_id)
   end
end

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :reviews, inverse_of: :user
end

答案 1 :(得分:1)

为什么不制作一个has_reviewed?用户类的方法?

e.g。

def has_reviewed?(reviewable)
   # query in here
end

然后你应该可以在你的控制器和你的观点中使用它。

答案 2 :(得分:0)

您需要为new和create执行此操作。否则,精明的用户将能够运行一个可以通过新操作的帖子。

我会将link_to放在helper或presenter对象中。它通常看起来像这样。

def create_or_edit_review_path(movie, current_user)
  return '' if current_user.blank?

  if current_user.review.present?
    #Generate review edit link
  else
    #generate new link
  end 
end

在你的所有观点之后,它只是

<%= create_or_edit_review_path(@movie, current_user) %>

然后在您的控制器中同时执行new和create,您可以执行之前的操作或只是重定向每个操作。

before_action :enforce_single_review, only: [:create, :new]

def enforce_single_review
  if current_user.review.present?
    redirect_to review_path(current_user.review)
  end
end

答案 3 :(得分:0)

以下是我提出的建议:

我使用find_by模型上的Review方法创建了一个实例方法来检索用户的电影评论:

class User < ActiveRecord::Base
  ....
  def movie_review(album)
    Review.find_by(user_id: self, album_id: album)
  end
end

设置回调时,此方法也很方便:

class ReviewsController < ApplicationController
  before_action :limit_review, only: [:new, :create]
  ....
  private
    def limit_review
      user_review = current_user.movie_review(@movie)

      if user_review.present?
        redirect_to edit_movie_review_path(@movie, user_review)
      end 
    end
end

创建了一个帮助方法,用于显示指向编辑创建审核的相应链接。非常感谢Austio和他的suggestion

module ReviewsHelper
  def create_or_edit_review_path(movie)
    user_review = current_user.movie_review(movie) if user_signed_in?

    if user_signed_in? && user_review.present?
      link_to "Edit review", edit_movie_review_path(movie, user_review)
    else
      link_to "Write a review", new_movie_review_path
    end
  end
end

最后,这就是我在视图模板中调用助手的方式:

....
<%= create_or_edit_review_path(@album) %>