【问题标题】:Rails: update votes_count after user voted on pinsRails:在用户对 pin 投票后更新 votes_count
【发布时间】:2014-11-09 15:54:52
【问题描述】:

我有一个非常简单的 rails 应用程序,用户可以在其中对 pin 进行投票。我实现的系统运行良好,但我希望通过 ajax 方法在每次投票后更新投票数。

这是我现在的投票系统:

在 app/controllers/pins_controller.rb 中:

def upvote
  @pin = Pin.friendly.find(params[:id])
  @pin.votes.create(user_id: current_user.id)
    respond_to do |format|
    format.json { render json: { count: @pin.votes_count } }
 end
end

在我的 app/views/pins/index.html.erb 中:

<%= link_to upvote_pin_path(pin), method: :post, remote: true do %>

        <% if pin.votes.where(user_id: current_user.id).empty? %>

            <span class="text-decoration: none;"><i class="fa fa-star"></i>

        <% else %>

            <span class="text-decoration: none;"><i class="fa fa-star" style="color:#c0392b"></i>

        <% end %>

<% end %>
            <span class="votes-count">
              <%= pluralize(pin.votes.count, "") %>
            </span>

因此,每当有人对 pin 进行投票时,只有在刷新页面后才能看到投票。有什么想法吗?

我知道我应该在我的视图中调用 upvote.js.erb 文件中的 ajax 方法,但这就是我迷路的地方。

【问题讨论】:

    标签: javascript jquery ruby-on-rails ruby ajax


    【解决方案1】:

    我个人更喜欢避免使用那些凌乱的 .js.erb 文件,尽管您当然可以这样做。但是,一旦您进行了大量的 Ajax 调用,您最终会得到一大堆文件。 Ryan Bates 对这项技术进行了精彩的截屏here

    要做到这一点,这是食谱。您需要在控制器操作中放置一个 respond_to 块。现在,无论请求如何进入,您都将重定向到 pin 路径,我假设在这种情况下是当前路径,它会重新加载页面。这就是你要避免的。

    默认情况下,Ajax 请求以 javascript 或 js 请求类型进入控制器。您可以根据需要切换该类型(JSON 是一种流行的替代方案),但现在让我们保持简单。所以为一个js请求配置respond_to块:

    # app/controllers/pins_controller.rb
    def upvote
      @pin = Pin.friendly.find(params[:id])
    
      if @pin.votes.create(user_id: current_user.id)
        respond_to do |format|
          format.html {
            flash[:notice] =  "Thanks for your recommendation."
            redirect_to(pin_path)
          }
    
          format.js {
            @count = @pin.votes.count.to_s
            render nothing: true, count: @count # anything else you put in here will be available in the `success` callback on the JQuery ajax method.
          }
        end
      else 
        format.html {
          flash[:notice] =  "Unable to process your request. Please try again."
          redirect_to(pin_path)
        }
    
        format.js {
          render nothing: true # anything else you put in here will be available in the `error` callback on the JQuery ajax method.
        }
      end
    end
    

    现在控制器已经传回了值,您需要在 Ajax 请求中检索它:

         $.ajax({
           .....
           success:function(data){
             $('span.votes-count').text(data.count)
           }
    

    当您通过此方法使用它们时,您将无法使用(至少)两件事。 Flash 消息,以及 ruby​​ 复数方法。要绕过第二个,您需要在控制器中使用 Ruby 复数形式并返回您想要的文本。要绕过第一个问题,您需要设置一些模仿 Rails flash 消息技术的 javascript,并将 flash 消息传递回 Ajax 调用。

    【讨论】:

    • 首先,感谢钢铁侠的详细解答。所以我将您的代码添加到我的控制器中。然后我在我的 javascript 文件中的 votes.js 文件中添加了 ajax 请求。我不确定将什么作为#my_target_element id。您能否详细说明我应该使用的 Ajax 请求?谢谢
    • 当然。我更改了成功调用以更符合您的示例。
    • 感谢您的努力,所以我更新了这个 ajax 请求,但它仍然需要刷新页面以显示更新的赞成票数。该死的......对不起:')
    • 不,它没有。我几乎每天都使用这种技术。如果您仍在苦苦挣扎,我建议您从 Ryan Bates Railscast 开始。
    • 明确地说,我不是在测试我给你的代码。您需要使该技术适应您的特定环境。
    【解决方案2】:

    您应该将您的 pinvotes 放在一个跨度内,其中包含一个用于在 ajax 完成后进行搜索的类

    $(".fa.fa-star").click(function(){
         var _this=$(this)
         $.ajax({
           .....
            success:function(msg){
                _this.parent().parent().find('.votes-count').html(msg); //Accesing the parent then you should acces a span to your votes
             }
         })
    })
    

    【讨论】:

    • 感谢您的回答但我还是想不通 - 我对 Rails 很陌生,对 ajax 功能更是陌生...我添加了 remote: true 到我的 upvote 按钮,但 votes_count 不是更新,这就是我需要通过我的 ajax 方法更新的内容
    • 我不知道 rails 是如何工作的,你能把 app/views/pins/index.html.erb 中的代码打印出来的 html 放上去吗?也许我可以在这方面提供更多帮助
    • 好的 - 所以我在 index.html.erb 中使用更多代码编辑了我的问题
    • 1.-
    • 好的,谢谢,我会调查一下。有消息通知你。再次感谢您的宝贵时间和建议
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 1970-01-01
    相关资源
    最近更新 更多