#ruby-on-rails #pins
#ruby-on-rails #пины
Вопрос:
Я реализовал простой способ, позволяющий пользователям голосовать за пины, но я хотел бы упорядочить пины по количеству голосов, вот моя система голосования:
приложение / контроллеры /pins_controller.rb
def upvote
@pin = Pin.find(params[:id])
@pin.votes.create
redirect_to(pins_path)
end
приложение / модели /vote.rb
class Vote < ActiveRecord::Base
belongs_to :pin
end
приложение / модели/pin.rb
has_many :votes, dependent: :destroy
И мой routes.rb выглядит так:
resources :pins do
member do
post 'upvote'
end
en
Итак, я хотел бы, чтобы мое приложение / views / pins / index.html.erb
чтобы отобразить пины с наибольшим количеством проголосовавших за меньшее количество проголосовавших.
Я знаю, что acts_as_votable предоставляет систему для этого, но поскольку я не использовал этот драгоценный камень для реализации своей системы голосования, я не уверен, что это хорошая идея использовать его.
Что вы думаете?
Мое приложение / views / pins /index.html.erb выглядит следующим образом:
<% @pins.each do |pin| %>
<div class="box panel panel-default">
<%= image_tag pin.image.url(:medium) %>
<div class="panel-body">
<p class="startupinfo">
<%= pin.startupname %><span class="reward"><i class="fa fa-heart"></i> <%= pin.reward %></p></span>
<p class="startupname"><%= pin.description %></p>
<p class="startuptag"><i class="fa fa-map-marker turquoise"></i> <%= pin.tag %> <i class="fa fa-tags turquoise"></i> <%= pin.city %><%= link_to upvote_pin_path(pin), method: :post do %> <i class="fa fa-chevron-circle-up fa-1x" style="color:#28c3ab"></i> <% end %>
<%= pluralize(pin.votes.count, "upvote") %></p>
<p class="users-edit">
<%= link_to pin_path(pin), class: "btn btn-success" do %> Tweet <% end %>
<% if pin.user == current_user %>
<%= link_to 'Edit', edit_pin_path(pin) %>
<%= link_to 'Delete', pin, method: :delete, data: { confirm: 'Are you sure?' } %></p>
<% end %>
</div>
</div>
<% end %>
НА ОСНОВЕ ОТВЕТА БАЛУ:
Я побежал:
rails generate migration add_votescount_to_pins votes_count:integer
rails generate migration add_countercache_to_votes counter_cache:integer
Я вручную обновил миграцию _add_votescount_to_pins.rb, так что это выглядит как:
class AddVotescountToPins < ActiveRecord::Migration
def change
add_column :pins, :votes_count, :integer
Pin.reset_column_information
Pin.includes(:votes).all.each do |pin|
Pin.update_counters(pin.id, :votes_count => pin.votes.size)
end
end
Я побежал:
rake db:migrate
Затем я добавил следующую строку в свой pins.controller.rb :
def index
@pins = Pin.all
@pins = Pin.order(votes_count: :desc)
end
Теперь мой файл schema.rb выглядит следующим образом:
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140704125839) do
create_table "pins", force: true do |t|
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.string "tag"
t.string "reward"
t.string "startupname"
t.string "city"
t.string "tweet"
t.string "logo"
t.string "website"
t.string "rewardcode"
t.string "logo_file_name"
t.string "logo_content_type"
t.integer "logo_file_size"
t.datetime "logo_updated_at"
t.integer "votes_count"
end
add_index "pins", ["user_id"], name: "index_pins_on_user_id"
create_table "startups", force: true do |t|
t.string "name"
t.text "description"
t.text "location"
t.text "tag"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.string "provider"
t.string "uid"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
create_table "votes", force: true do |t|
t.integer "pin_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "counter_cache"
end
end
Но мой индекс пин-кода по-прежнему не упорядочен по количеству голосов, проголосовавших за!
Есть идеи?
Ответ №1:
Итак, когда вы отказываетесь голосовать, это уничтожает?
Вы можете добавить votes_count
столбец integer к pins, а затем добавить counter_cache
к голосованию.
class Vote < ActiveRecord::Base
belongs_to :pin, counter_cache: true
end
Это увеличит количество голосов по pin-коду, когда кто-то проголосует за него.
Затем просто запрос на основе этого
@pins = Pin.order(votes_count: :desc)
В процессе миграции вы захотите обновить votes_count на основе существующих голосов.
add_column :pins, :votes_count, :integer, default: true
Pin.reset_column_information
Pin.all.each do |pin|
Pin.reset_counters(pin.id, :votes)
end
Комментарии:
1. У меня нет системы голосования «против», я хочу предоставить пользователю возможность голосовать только «за». Я попробую ваш метод и буду держать вас в курсе. Спасибо, кстати
2. Я обновил свой вопрос тем, что вы сказали, но он по-прежнему не упорядочен, можете ли вы проверить, не допустил ли я где-нибудь ошибку?
3. Удалите эту строку
@pins = Pin.all
, также вам не нуженcounter_cache
целочисленный столбец в Pins — потому что имя класса — этоVote
он будет искать вPin
столбце с именемvotes_count
это ваш столбец кэша счетчика4. Я удаляю эту строку и заменяю ее на @pins = Pin.order(votes_count: :desc), но она по-прежнему упорядочивается не так, как я хочу. Я обновил свой pins / index.html.erb в своем вопросе — даже если я не думаю, что ошибка исходит из этого файла.
5. Итак, я должен удалить целое число counter_cache из моих столбцов Pins? Я обновил свой вопрос своим файлом schema.rb — Потому что у меня нет целочисленного столбца counter_cache для Pins — как и для столбцов votes (см. schema.rb, обновленный в моем вопросе)
Ответ №2:
Чтобы добиться этого без кеширования счетчика, вы можете попробовать это:
@pins = Pin.joins(:votes).select('pins.*, COUNT(votes.id) AS vote_count').group('votes.pins_id').order('vote_count DESC')
Комментарии:
1. Где я должен это реализовать? В моем pins_controller.rb — внутренний индекс?
2. Да, если именно там вы хотите показать пины, отсортированные по голосам