ajax成功与错误问题

时间:2015-06-23 08:47:46

标签: ruby-on-rails ajax

我有可以投票的帖子,用户只能为帖子投票一次。我想在点击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

1 个答案:

答案 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