我有我的应用设置,用户可以在其中为电影撰写评论。我想做的是限制用户每部电影只创建一个评论。我已经设法在我的评论控制器中实现了这一点:
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?方法中的查找?我觉得有更好的方式来编写它,但无法确定最合适的修复方法。
答案 0 :(得分:2)
(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) %>