2015-09-26 117 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 
相關問題