2016-08-05 8 views
0

In meiner App wird es viele Dinge geben, die users oben oder unten abstimmen können (in einer Reddit-ähnlichen Weise). Dies wird eine Upvote/Downvote-Struktur für jokes, recipes, rules usw. enthalten. Im Moment versuche ich, eine polymorphe votes mit dem joke Modell als ein Beispiel einzurichten.Rails polymorphe Abstimmungsstruktur

I votes als polymorphe Variable hinzugefügt haben, wie in meinem schema zu sehen:

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" 

Und ich fügte eine float Spalte meiner jokes Tabelle für rank.

Ich habe ein vote Modell:

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 

und machte das entsprechende Updates zu meinem joke Modell:

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 

Und mein user Modell:

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

Ich habe ein votes_controller wie folgt:

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 

Und schließlich diese _voter.html.erb Teil:

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

ist auf meiner otherjokes/kids.html.erb Seite gezeigt:

<% @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 %> 

ich die folgenden Anpassungen an meine routes auch gemacht haben:

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 

Gerade jetzt, wenn ich versuche, über einen Witz abzustimmen, bekomme ich unknown attribute 'joke' for Vote. genannt auf der @vote = current_user.votes.create(value: new_value, joke: @joke) Linie am Ende meiner votes_controller.

Ich würde gerne dieses System so laufen lassen, dass es auf andere zukünftige Modelle angewendet werden kann, die Abstimmung erfordern und (wenn möglich) auch "den Ruby-Weg" machen. Kann mir jemand helfen, das richtig zu strukturieren?

Antwort

0

Wie der Fehler angibt, ist joke kein Attribut von Vote. Da es sich um eine polymorphe Assoziation handelt, haben Sie ihm den generischen Namen votable gegeben. Verwenden Sie dies, um eine Vote für eine Joke zu erstellen.

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

votable_idvotable_type und wird automatisch durch den Rahmen abgeleitet werden.

+0

Geht das in den 'jokes_controller' oder' votes_controller'? Wenn ich es in den Index acton des Witze-Controllers setze, bekomme ich einen Fehler in dieser Zeile und sage 'undefined lokale Variable oder Methode' neuer_Wert 'für # ' – Liz

+0

Es ist der Ersatz für die fast identische Zeile in Ihrem votes_controller. Es ist die Zeile, die den Fehler angezeigt hat. – AmShaegar

+0

Das änderte den Fehler in 'undefinierte Methode 'update_vote' für # '. – Liz