我发现自己试图尽可能地将代码分段为控制器逻辑的回调。但我开始担心性能问题。在下面的示例中,我必须在点击投票#update时查询相同的投票实例3x。反正有没有传递一个对象,以便我可以维护我的回调但只查询一次db?我在Rails中错过了一些机制吗?
class VoteController < ApplicationController
#Access limitations etc.
before_action :authenticate_user!
before_action :correct_user_vote, only: [:edit, :update]
before_action :election_concluded_check, only: [:update]
def edit
@vote = Vote.find(params[:id])
end
def update
@vote = Vote.find(params[:id])
if !@vote.nil? && @vote.update_attributes(vote_params)
redirect_to party_path(@vote.party_id)
else
flash[:error] = "Something went wrong"
redirect_to root_path
end
end
private
def correct_user_vote
vote = Vote.find(params[:id])
if vote.nil? || current_user.id!=vote.user_id
flash[:error] = "Something went wrong"
redirect_to root_path
end
end
def election_concluded_check
# Do not allow updating of votes if party.concluded
vote = Vote.find(params[:id])
if vote.nil? || vote.election.concluded
flash[:error] = "Something went wrong"
redirect_to root_path
end
end
def vote_params
params[:vote].permit(:candidate_id,:note)
end
end
答案 0 :(得分:2)
将您的投票加载到before_action
中的实例变量中,然后在随后的所有before_action
中使用它:
class VoteController < ApplicationController
before_action :authenticate_user!
before_action :find_vote, only: [:edit, :update]
before_action :correct_user_vote, only: [:edit, :update]
before_action :election_concluded_check, only: [:update]
def edit
end
def update
if @vote.update_attributes(vote_params)
redirect_to party_path(@vote.party_id)
else
flash[:error] = "Something went wrong"
redirect_to root_path
end
end
private
def find_vote
@vote = Vote.find(params[:id])
end
def correct_user_vote
if current_user.id != @vote.user_id
flash[:error] = "Something went wrong"
redirect_to root_path
end
end
def election_concluded_check
# Do not allow updating of votes if party.concluded
if @vote.election.concluded
flash[:error] = "Something went wrong"
redirect_to root_path
end
end
end
您可以这样做的原因是实例变量(以@
开头的变量)可以在同一对象的方法之间访问。因此,您可以在一个方法(@vote
)中设置find_vote
,然后在同一对象的其他方法中访问它(例如update
)。在这种情况下,@vote
仅在find_vote
方法中加载一次。
另请注意,在@vote
中加载before_action
实例变量后,您不再需要在edit
方法中执行任何操作,这是此方法的一个很好的副作用
作为旁注,假设Vote
是ActiveRecord::Base
子类,当您执行@vote = Vote.find(id)
时,@vote
对象永远不会是nil
,因为如果ActiveRecord::Base#find
找不到您要求的记录,则会引发异常。因此,我们确实无需检查@vote.nil?
。
答案 1 :(得分:-1)
通常的技术是使用在第一次访问时缓存对象的方法替换变量。例如:
def edit
@vote = vote
end
private
def vote
@_vote ||= Vote.find(params[:id])
end
def correct_user_vote
if vote.nil? || current_user.id != vote.user_id
flash[:error] = "Something went wrong"
redirect_to root_path
end
end
不幸的是,Rails认为使用实例变量将信息传递给您的视图是个好主意,因此您需要注意如何命名缓存值(因此@_vote
而不是@vote
)