2013-03-11 4 views
2

Мне нужен совет по системе голосования в рельсах, который ежемесячно распознает верхний избиратель. У меня есть система, которая работает, но новичок в рельсах, я уверен, что есть более эффективные методы. Ниже представлена ​​упрощенная версия моей текущей установки (контроллер кода опущены):Ruby on Rails - ежемесячный топ-геттер

class Charity < ActiveRecord::Base 
    has_many :votes 
end 

class Vote < ActiveRecord::Base 
    belongs_to :charity 
end 

Моя схема выглядит следующим образом:

ActiveRecord::Schema.define(:version => 20130310015627) do 
    create_table "charities", :force => true do |t| 
    t.string "name" 
    t.text  "description" 
    t.date  "last_win" 
    t.datetime "created_at", :null => false 
    t.datetime "updated_at", :null => false 
    end 
    create_table "votes", :force => true do |t| 
    t.integer "charity_id" 
    t.datetime "created_at", :null => false 
    t.datetime "updated_at", :null => false 
    end 
end 

Я буду использовать «когда» драгоценный камень, чтобы запустить хрон определить ежемесячный победитель и обновить столбец «last_win» таблицы благотворительных услуг. Следующий код, где я сомнение своей эффективности:

vote_counts = Vote.count(:group => "charity_id") 
most_votes = vote_counts.values.max 
winning_ids = vote_counts.map{|k,v| v == most_votes ? k :nil }.compact 
charities = Charity.find(winning_ids) 
charities.each {|charity| charity.update_attributes(:last_win => Date.today)} 

Я уверен, что есть много способов сделать это лучше, и хотели бы некоторые предложения. Если у вас есть предложения по лучшим способам создания таблицы голосов/ассоциаций, это тоже будет оценено.

Спасибо заранее, CRS

+0

Может ли быть только один победитель? Похоже, ваш код обрабатывает связи. –

+0

Может быть несколько победителей. Задача cron будет работать в первый день месяца. Я настрою его только на подсчет голосов за предыдущий месяц. – Clay

ответ

2

Something как это:

Если есть только один победитель, это будет работать, я думаю, что

winner_id = Vote.group(:charity_id).order("count(*) desc").pluck(:charity_id).first 
Charity.find(winner)id).update_attribute!(:last_win => Date.today) 

Вы можете изменить его для связи:

most_votes = Vote.group(:charity_id).order("count(*) desc").count.first[1] 
winners = Vote.group(:charity_id).having("count(*) = ?", most_votes).pluck(:charity_id) 

Charity.where(:id => winners).update_all(:last_win => Date.today) 

Убедитесь, что все правильно индексируется в базе данных,

Вы, вероятно, может оптимизировать его больше, но SQL будет получить сложнее.

+0

Спасибо за помощь. И спасибо, что напомнили мне об индексировании. – Clay

1

Последние две линии могут быть:

Charity.where(id:winning_ids).update_all(last_win:Date.today) 

Что бы перевести в одну команду обновления SQL, вместо того, чтобы выдавать команду обновления для каждой выигрышной благотворительностью.

Первая часть, где вы идентифицируете благотворительные организации, выглядит хорошо, и поскольку вы используете ее как работу cron, вам, вероятно, все равно, если это займет несколько минут.

Однако, если вы хотите, чтобы показать значения в реальном времени, вы можете добавить after_create крюк Vote обновить счетчик для его владельца благотворительности (возможно, в другой таблице):

class Vote < ActiveRecord::Base 
    belongs_to :charity 
    after_create :increment_vote_count 
    CharityVote.where(year:Time.now.year, month:Time.now.month, 
    charity_id:self.charity_id).first_or_create.increment!(:counter) 
end