2015-04-26 6 views
0

У меня есть элемент модели, на который пользователи могут проголосовать, создав новый UpVote или DownVote. Когда создается UpVote или Downvote, он записывает IP-адрес пользователя и идентификатор Item. Я хочу перечислить массив из первых 100 элементов, которые не были проголосованы за текущий ip пользователя.Есть ли более эффективный способ получения этого массива?

До сих пор, вот что у меня есть:

схема

create_table "up_votes", force: true do |t| 
    t.string "ip" 
end 

create_table "down_votes", force: true do |t| 
    t.string "ip" 
end 

модель

class Item < ActiveRecord::Base 

    def up_votes_array 
    self.up_votes.map(&:ip).to_a 
    end 

    def down_votes_array 
    self.down_votes.map(&:ip).to_a 
    end 

    def up_voted?(ip) 
    self.up_votes_array.include? ip 
    end 

    def down_voted?(ip) 
    self.down_votes_array.include? ip 
    end 

контроллер

@not_voted = Item.where(show: true).select { |item| !item.up_voted?(request.remote_ip) }.select { |thing| !item.down_voted?(request.remote_ip) }.sort_by(&:alphabetical).reverse.first(100).shuffle 

Это работает, но есть кое-что обо всем, что кажется, что излишне сложным, и я боюсь, что, как растет моя база данных, она может стать неэффективным. Есть ли более эффективный способ получить этот массив?

Я использую Rails 4 и Sqlite3.

+0

что 'Thing' здесь. И что это за связь с Item? – kiddorails

+0

К сожалению, я перепутал его с другим столом, который у меня есть. Предполагается, что это «Элемент». –

ответ

2

Я думаю, что идеальный запрос для этого будет что-то вроде этого:

Item.where(show: true).joins(:up_votes).joins(:down_votes).where('up_votes.ip != ?', request.remote_ip).where('down_votes.ip != ?', request.remote_ip).limit(100)

Это создаст оптимальный запрос и загрузить 100 строк в памяти, в отличие от запроса данного где он загружает всю таблицу для Item, и все итерации на всем протяжении вверх и вниз, чтобы проверить.

Вы, вероятно, также клуб запрос вместе: Item.where(show: true).joins(:up_votes).joins(:down_votes).where('up_votes.ip != ? and down_votes.ip != ', request.remote_ip, request.remote_ip).limit(100)

+0

Будет ли это работать? Что делать, если элемент имеет up_vote как из сеанса ip, так и из другого ip? Он имеет хотя бы один up_vote, который равен! = Ip, поэтому он будет выбран, когда этого не должно быть. – SteveTurczyn

+0

Он не будет выбирать этот элемент, если у любого из его upvote или downvote есть request.remote_ip, даже если какое-то другое upvote или downvote of * that * item имеет некоторый ip. Он должен возвращать запрос вроде: 'select * from items inner join up_votes on items.id = up_votes.item_id inner join down_votes на items.id = down_votes.item_id где up_votes.ip <>" 127.0.0.1 "и down_votes.ip < > "127.0.0.1" limit 3'. Дать ему шанс. – kiddorails

+0

Прохладный. Всегда образование, висящее здесь. :) – SteveTurczyn