George_Fal 2014-06-14 06:00 采纳率: 0%
浏览 44

AJAX渲染局部

I am trying to accomplish what I think to be the most direct, though certainly not the most elegant, replication of a reddit style vote button. I have code that works without the AJAX, but I would like users to be able to click the vote buttons and they change appropriately without reloading the page (Hence the AJAX).

The problem occurs when I try to remove the vote button clicked on and replace with the appropriate 'highlighted' vote button. The reason I am replaceing the vote button is because I need to change it to a button that will unvote if clicked on.

(I have simplified this to just handle just upvoting since downvoting is the same mexhanic). Here is my view:

  <% @posts.each do |post| %>
    <%= post.content %>
    <% if current_user.voted_as_when_voted_for post %>
      <%= render 'upvoted', post: post %>
    <% else %>
      <%= render 'upvote', post: post %>
    <% end %>
  <% end %>

The voted_as_when_voted_for method returns true if they have upvoted the post. Here is the upvote and upvoted forms:

<%= link_to image_tag('upvoted.png', size: '18'), remove_like_post_path(post), method: :put, remote: true, id: "upvoted#{post.id}" %>

<%= link_to image_tag('upvote.png', size: '18'), like_post_path(post), method: :put, remote: true, id: "upvote#{post.id}" %>

Here is my controller:

def upvote
  @post = Post.find(params[:id])
  @post.liked_by current_user
  respond_to do |format|
    format.html { redirect_to @post.parent }
    format.js   {}
  end
end

def remove_upvote
  @post = Post.find(params[:id])
  @post.unliked_by current_user
  respond_to do |format|
    format.html { redirect_to @post.parent }
    format.js   {}
  end
end

upvote.js.erb: and upvoted.js.erb:

$('#upvote<%= @post.id %>').remove().append('<%= j render("upvoted") %>');

$('#upvoted<%= @post.id %>').remove().append('<%= j render("upvote") %>');

With those files I get the following console errors:

PUT http://localhost:3000/posts/96/like 500 (Internal Server Error) 

NameError in Posts#upvote

undefined local variable or method `post' for #<#<Class:0x007fde1836cbf0>:0x007fde18c00af0>

_upvote.html.erb and _upvoted.html.erb

<%= link_to image_tag('upvote.png', size: '18'), like_post_path(post), method: :put, remote: true, id: "upvote#{post.id}" %>

<%= link_to image_tag('upvoted.png', size: '18'), like_post_path(post), method: :put, remote: true, id: "upvoted#{post.id}" %>

I also tried something like this based on the link below:

$('#upvote<%= @post.id %>').remove().after('<%= j render "upvoted", post: @post %>');

When I use that code, the upvote is succesfully removed, but the upvoted form is not added on. So it seems that I need to use the instance variable, but something is still not quite working.

What am I missing??

This person seemed to have a similar problem: Rails Ajax Render Partial

  • 写回答

2条回答 默认 最新

  • weixin_33713350 2014-06-14 07:34
    关注

    DRY

    Doesn't look very DRY to me

    You could remove a lot of the duplicate code by making better use of your HTTP Verbs - by defining a delete route (for downvote) & post route (for upvote):

    #config/routes.rb
    resources :posts do
       match :vote, via: [:post, :delete] #-> domain.com/posts/14/vote
    end
    
    #app/controllers/posts_controller.rb
    Class PostsController < ActiveRecord::Base
        respond_to :js, :html
        def vote
           @post = Post.find params[:id]
    
           if request.post? 
              @post.liked_by current_user
           elsif request.delete?
              @post.unliked_by current_user
           end
    
           respond_with @post
        end
    end
    

    Views

    This will allow you to create the following JS & views:

    #app/views/posts/vote.js.erb
    $("<%= 'upvote##{@post.id}' %>").html('<%= j render "vote", locals: { post: @post } %>');
    

    -

    #app/views/posts/_vote.html.erb
    image = current_user.voted_as_when_voted_for(post) ? "downvote.png" : "upvote.png"
    method = current_user.voted_as_when_voted_for(post) ? :delete : :post
    
    <%= link_to image_tag(image, size: '18'), post_vote_path(post), method: method, remote: true, id: "upvote#{post.id}" %>
    

    -

    #app/views/posts/show.html.erb
    <% @posts.each do |post| %>
        <%= post.content %>
        <%= render 'vote', post: post %>
    <% end %>
    

    Fix

    After looking at your code, I would look at the error for hints as to what the issue might be:

    undefined local variable or method `post'

    The problem seems to be called in your upvote action, which will have the partial upvoted like this:

    $('#upvoted<%= @post.id %>').remove().append('<%= j render("upvote") %>');
    

    The problem is this partial requires the post local variable. So the issue is that you're not passing the @post to your partial via the locals argument

    My code above addresses this, but in order to resolve it, you should just use locals: { post: @post }

    评论

报告相同问题?

悬赏问题

  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?