Rails多态投票结构

时间:2016-08-05 17:48:45

标签: ruby-on-rails

在我的应用程序中,users可以向上或向下投票(以类似Reddit的方式)。这将包括jokesrecipesrules等的upvote / downvote结构。现在我正在尝试使用{{1}设置多态votes以模型为例。

我添加了joke作为多态变量,可以在我的votes中看到:

schema

我在create_table "votes", force: :cascade do |t| t.integer "value" t.integer "user_id" t.integer "voteable_id" t.string "voteable_type" t.datetime "created_at", null: false t.datetime "updated_at", null: false end add_index "votes", ["user_id"], name: "index_votes_on_user_id" add_index "votes", ["voteable_type", "voteable_id"], name: "index_votes_on_voteable_type_and_voteable_id" 的{​​{1}}表中添加了float列。

我创建了一个jokes模型:

rank

并对我的vote模型进行了适当的更新:

class Vote < ActiveRecord::Base
  belongs_to :user
  belongs_to :voteable, polymorphic: true
  after_save :update_vote

  private
  def update_joke
    vote.update_rank
  end
end

我的joke型号:

class Joke < ActiveRecord::Base
  belongs_to :user
  has_many :votes, as: :voteable, dependent: :destroy
  default_scope { order('rank DESC')}
  def up_votes
    votes.where(value: 1).count
  end
  def down_votes
    votes.where(value: -1).count
  end
  def points
    votes.sum(:value)
  end
  def update_rank
    new_rank = points
    update_attribute(:rank, new_rank)
  end
end

我有user如下:

class User < ActiveRecord::Base
  ...
  has_many :jokes, dependent: :destroy
  has_many :votes, dependent: :destroy
end

最后这个votes_controller部分:

class VotesController < ApplicationController

  def up_vote
    update_vote(1)
    redirect_to :back
  end

  def down_vote
    update_vote(-1)
    redirect_to :back
  end

  private
  def update_vote(new_value)
    @joke = Joke.find(params[:joke_id])
    @vote = @joke.votes.where(user_id: current_user.id).first

    if @vote
      @vote.update_attribute(:value, new_value)
    else
      @vote = current_user.votes.create(value: new_value, joke: @joke)
    end
  end
end

显示在我的_voter.html.erb页面上:

<div class="text-center col-xs-1">
  <% if current_user %>
    <div class="width: 100%"><%= link_to " ", joke_up_vote_path(joke), class: 'glyphicon glyphicon-chevron-up', method: :post, style: "margin-right: 0; margin-left: 0" %></div>
  <% else %>
    <div class="width: 100%"><%= link_to " ", new_user_session_path, class: 'glyphicon glyphicon-chevron-up', method: :post, style: "margin-right: 0; margin-left: 0" %></div>
  <% end %>
  <div class="width: 100%"><h3 style="margin-top: 0; margin-bottom: 0"><strong><%= joke.points %></strong></h3></div>
  <% if current_user %>
    <div class="width: 100%"><%= link_to " ", joke_up_vote_path(joke), class: 'glyphicon glyphicon-chevron-down', method: :post, style: "margin-right: 0; margin-left: 0" %></div>
  <% else %>
    <div class="width: 100%"><%= link_to " ", new_user_session_path, class: 'glyphicon glyphicon-chevron-down', method: :post, style: "margin-right: 0; margin-left: 0" %></div>
  <% end %>
</div>

我对otherjokes/kids.html.erb进行了以下调整:

<% @jokes.each do |joke| %>
  <div class="row">
    <% if joke.approved == true && joke.kids == true %>

    <%= render partial: 'votes/voter', locals: { joke: joke } %>

    <div class="col-xs-11"> <!-- non vote container -->

      <h2 id="joke-title" style="margin-top: 0px">
        <%= joke.title %>
        <% if joke.kids == true %>
          <%= image_tag 'icon_kids.jpg', style: "height: 25px; margin-left: 10px" %>
        <% end %>
        <% if joke.mixed == true %>
          <%= image_tag 'icon_mixed.jpg', style: "height: 25px; margin-left: 10px" %>
        <% end %>
      </h2>

      <p id="joke-body"><%= joke.body %></p>
      <p><strong>Submitted by: <%= joke.user.first_name %></strong></p>
      <% if current_user && (current_user == joke.user || current_user.admin) %>
        <%= link_to edit_joke_path(joke) do %>
          <span style="color: blue" class="glyphicon glyphicon-pencil" aria-hidden="true"></span><span style="color: blue">Edit Joke</span>
        <% end %>
        <%= link_to joke_path(joke), data: {:confirm => 'Are you sure?'}, :method => :delete do %>
          <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>Delete Joke
        <% end %>
      <% end %>
    </div> <!-- non vote container -->
  </div> <!-- joke row -->
  <% end %>
  <div class="row text-center">
    <hr style="width: 50%; margin-top: 30px; margin-bottom: 30px">
  </div> <!-- row -->

<% end %>

现在,当我尝试对一个笑话进行投票时,我会在routes末尾的 resources :jokes do patch :approve, on: :member patch :reject, on: :member post '/up-vote' => 'votes#up_vote', as: :up_vote post '/down-vote' => 'votes#down_vote', as: :down_vote end 行调用unknown attribute 'joke' for Vote.

我希望这个系统运行的方式可以应用于其他需要投票的未来模型,并且(如果可能的话)“Ruby方式”。任何人都可以帮我正确地构建这个吗?

1 个答案:

答案 0 :(得分:0)

如错误所述,joke不是Vote的属性。因为它是一个多态关联,所以你给它起了通用名votable。使用此选项可为Vote创建Joke

@vote = current_user.votes.create(value: new_value, votable: @joke)

votable_idvotable_type将由框架自动派生。