1

次のコードは次のことを行います。ユーザーが投票した場合は、削除投票フォームと投票ダウンフォームを表示します。ユーザーが反対票を投じた場合は、賛成票削除票を提示します。それ以外の場合は、投票フォームと投票フォームを表示します(質問が長くなりすぎないように、コードの一部を省略しました)。

ここに画像の説明を入力してください

(シナリオ:ユーザーが反対票を投じた):

post_controller.rb:

  def show
    @post = Post.find(params[:id])
    @replies = @post.replies.paginate(page: params[:page])
    @reply = @post.replies.build
    @vote = Vote.new
    store_location
  end

投票_コントローラー.rb:

class VotesController < ApplicationController
 before_filter :signed_in_user

 def create
    @votable = find_votable

    # Destroy the vote first in case the user already voted
    if already_voted?
      @vote = @votable.votes.find_by_user_id(current_user.id)
      @vote.destroy
    end

    @vote = @votable.votes.build(params[:vote])
    @vote.user_id = current_user.id
    @votable.save

    respond_to do |format|
      format.html { redirect_back }
      format.js
    end
  end

  def destroy
    @votable = find_votable

    @vote = @votable.votes.find_by_user_id(current_user.id)
    @vote.destroy
    @votable.reload

    respond_to do |format|
      format.html { redirect_back }
      format.js
    end
  end


  private

    def find_votable
      params.each do |name, value|
        if name =~ /(.+)_id$/
          return $1.classify.constantize.find(value)
        end
      end
      nil
    end

    def already_voted?
      @votable.votes.exists?(:user_id => current_user.id)
    end
end

投稿/vote_form

<div class="vote-form">
  <% if @post.votes.exists?(:user_id => current_user.id) %>
    <% if @post.votes.find_by_user_id(current_user.id).polarity == -1 %>
      <%= form_for ([@post, @vote]), remote: true do |f| %>
        <%= f.hidden_field :polarity, value: 1 %>
        <div class="form-actions">
          <%= button_tag type: :submit, class: "btn btn-small vote" do %>
            <i class="icon-thumbs-down"></i> Vote up
          <% end %>
        </div>
      <% end %>

      <%= form_for ([@post, @post.votes.find_by_user_id(current_user.id)]),
                                                           method: :delete,
                                                           remote: true do |f| %>
        <div class="form-actions">
          <%= button_tag type: :submit, class: "btn btn-small btn-primary unvote" do %>
            <i class="icon-thumbs-up"></i> Vote down
          <% end %>
        </div>
      <% end %>
    <% end %>

投票/create.js:

$('#<%= @votable.class.name.downcase %>-<%= @votable.id %> .vote-form').html(
  "<%= escape_javascript(render('shared/delete_vote')) %>"
);

shared / _delete_vote.html.erb:

<% if @votable.votes.find_by_user_id(current_user.id).polarity == -1 %>
  <%= form_for ([@votable, @votable.votes.new]), remote: true do |f| %>
    <div class="form-actions">
      <%= button_tag type: :submit, class: "vote-down btn btn-small" do %>
        <i class="icon-thumbs-up"></i> Vote up
      <% end %>
    </div>
  <% end %>

  <%= form_for ([@votable, @vote]), method: :delete, remote: true do |f| %>
    <div class="form-actions">
      <%= button_tag type: :submit, class: "vote-up btn btn-small btn-primary" do %>
        <i class="icon-thumbs-up"></i> Vote down
      <% end %>
    </div>
  <% end %>
<% end %>

したがって、[下に投票]をクリックしてすぐに(ページを更新せずに)投票するとこのエラーが発生することを除いて、すべてが正常に機能するようになりました。

ActionView::Template::Error (undefined method `polarity' for nil:NilClass):
    1: <% if @votable.votes.find_by_user_id(current_user.id).polarity == 1 %>
    2:   <%= form_for ([@votable, @vote]), method: :delete, remote: true do |f| %>

何が問題なのですか?

編集:

エラーメッセージの行が問題であることに気づきました(ではありません@votable):

<% if @votable.votes.find_by_user_id(current_user.id).polarity == 1 %>

奇妙なことに、私はそれがと同じだと思いました

<% if @post.votes.find_by_user_id(current_user.id).polarity == 1 %>
4

1 に答える 1

1

問題はここにあると思います:

def destroy
  @votable = find_votable

  @vote = @votable.votes.find_by_user_id(current_user.id)
  @vote.destroy
  @votable.reload

  respond_to do |format|
    format.html { redirect_back }
    format.js
  end
end

現在のユーザーの投票を破棄したため、ビュー内で見つけることができません。

@votable.votes.find_by_user_id(current_user.id).polarity

そのため、極性はnilで呼び出されます。投票操作のロジックを言い換える必要があります。

編集:

最も簡単な解決策として、あなたは置き換えることができます

if @votable.votes.find_by_user_id(current_user.id).polarity == -1

if @votable.votes.find_by_user_id(current_user.id).blank?
于 2012-12-02T06:18:22.667 に答える