2015-09-26 80 views
1

我有我的应用程序设置,用户可以在其中为电影撰写评论。我想要做的是限制用户为每部电影创建一个评论。我已经成功在我的评语控制器来完成这个像这样:只允许用户为每部电影创建一个评论

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 

如果我现在有麻烦在翻译这个相同的逻辑到我与我的处置制定和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

这就是我想出了:

我创建了一个实例方法使用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 

,最后这就是我所说的助手在我的视图模板(S):

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

嗨,我有一个类似的例子,但我有点困惑。你有@album或@movie吗? – jedi

1

为什么不做一个has_reviewed?方法在你的用户类?

例如

def has_reviewed?(reviewable) 
    # query in here 
end 

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

+0

我想这样做的,但最大的挑战。因此对我来说,如何去从模型中获取'current_user'。 –

+0

这是一个用户类的方法,所以如果你把它当作current_user.has_review?(可查看),你会得到当前用户 – DanSingerman

0

你会想为新建和创建做到这一点。否则,一个精明的用户将能够运行一个帖子,通过你的新动作。

我会把link_to放在助手或演示者对象中。它通常看起来像这样。

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) %> 

然后在您的控制器,为新的和创建你既可以一个动作之前或只是每次重定向做。

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 
+0

对于这个帮助方法,你需要在开始时使用“def”这个词,对吗? –

+0

绝对会编辑。 – Austio

+0

我也应该注意到,一个用户'has_many'评论。所以基本上对于我得到的那个帮助器方法的第三行,对于#的'undefined method'review'是因为它不是'has_one'关联。 –

2

Why not use a validation

#app/models/review.rb 
class Review < ActiveRecord::Base 
    validates :movie_id, uniqueness: { scope: :user_id, message: "You've reviewed this movie!" } 
end 

这是考虑到你review模型belongs_to :movie


你也可以使用一个ActiveRecord的回调:

#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 

有没有什么办法可以改进has_reviewed中的查找?方法?

def has_reviewed? 
     redirect_to album_reviews_path, notice: "You've already written a review for this album." if current_user.reviews.exists?(movie: @movie) 
    end 
相关问题