我有可以投票的帖子,用户只能为帖子投票一次。我想在点击upvote按钮时动态更改投票的价值,所以我使用了ajax。这是我的代码:
控制器
def like
user = params[:user_id]
idee = params[:idee_id]
if Vote.exists?(:user_id => user, :idee_id => idee)
redirect_to :back, :notice => "Vous avez déjà voté pour cette idée"
else
Vote.create({ idee_id: idee, user_id: user})
redirect_to :back, :notice => "Merci d'avoir voté"
end
end
查看
<% if @idee.votes.count == 0 %>
<div class="upvote col-lg-2">
<div class="heart black hidden-xs">
<p class="like"><%= @idee.votes.count %></p>
<%= link_to "up", {controller: "vote", action: "like", user_id: @current_user, idee_id: @idee}, :method => :post, :remote => true, :class => "upvote-link" %>
</div>
</div>
<% else %>
<div class="upvote col-lg-2">
<div class="heart hidden-xs">
<p class="like"><%= @idee.votes.count %></p>
<%= link_to "up", {controller: "vote", action: "like", user_id: @current_user, idee_id: @idee}, :method => :post, :remote => true, :class => "upvote-link" %>
</div>
</div>
<% end %>
JS
$('.upvote-link')
.bind('ajax:success', function(evt, data, status, xhr) {
$('.like').html(parseInt($('.like').html(), 10) + 1)
if ($(".heart").hasClass("black")) {
$(".heart").removeClass("black");
}
})
.bind('ajax:error', function(evt, xhr, status, error) {
});
问题在于,当我点击10次时,视图将显示10票,但数据库中的计数为1.我相信ajax:错误没有考虑到并且它总是递增视图< / p>
修改
协会
Idee
has_many :votes, dependent: :destroy
belongs_to :user
投票
belongs_to :idee
belongs_to :user
用户
has_many :idees, dependent: :destroy
has_many :votes, dependent: :destroy
答案 0 :(得分:1)
如果你正在进行ajax调用,控制器不应该进行任何重定向,因为这只对html请求有意义。对于您想要处理的每种类型的请求,您应该有一个respond_to
块。
两个重定向(创建投票时和不投票时)将被ajax视为成功。通常,无论是否创建新投票,如果您的控制器通过使用成功代码发回一些数据来响应,那么ajax会将其视为成功。如果您的服务器遇到异常,或者故意返回错误代码,您只会收到错误代码,这在我看来不是解决这个问题的正确方法。
更好的解决方法是让控制器发回html以获取更新的投票按钮,ajax用该代码替换现有的投票按钮。他们不必将您的应用程序逻辑,格式,样式等编码到您的JavaScript中。事实上,除了远程link_to
生成的内容之外,您根本不需要任何javascript我会这样做:
#in view
<%= render :partial => "idees/vote_button", :locals => {:user => @current_user, idee => @idee}
#new partial, app/views/idees/vote_button
<% if @user.votes.find_by_idee_id(@idee.id) %>
<div class="heart hidden-xs">
<p class="like"><%= @idee.votes.count %></p>
<%# html for a disabled vote button, ie not actually a form, but just a greyed out graphic or something %>
</div>
<% else %>
<div class="heart black hidden-xs">
<p class="like"><%= @idee.votes.count %></p>
<%= link_to "up", {controller: "vote", action: "like", }, :method => :get, :remote => true, :class => "upvote-link" %>
</div>
<% end %>
#controller
def like
if @user = User.find_by_id(params[:user_id]) && @idee = Idee.find_by_id(params[:idee_id])
if Vote.exists?(:user_id => @user.id, :idee_id => @idee.id)
@notice = "Vous avez déjà voté pour cette idée"
else
Vote.create({ idee_id: @idee.id, user_id: @user.id})
@created = true
@notice = "Merci d'avoir voté"
end
else
@notice = "<french for \"Sorry, we couldn't find that user or idee\">"
end
respond_to do |format|
format.html do
redirect_to :back, :notice => @notice
end
format.js do
if @created
render :partial => "idees/vote_button", :locals => {:user => @user, idee => @idee}
end
#do something with "notice"? update a div with the contents? put it in an alert?
end
end
end
#javascript
#don't need any -it's all done by the remote link and the format.js block in the controller