Chciałbym, aby użytkownik miał możliwość tylko jednokrotnego zagłosowania na dany post. Napisałem prostą walidację, lecz skrypt zawsze “przepuszcza” dane.
EDIT: Dobra, poradziłem sobie. Dopiero teraz dotarło do mnie, że używanie tu self nie ma dużego sensu.
EEDIT2: Napisałem tak i działa, lecz sposób nie dokońca mnie satysfakcjonuje… errors.add_to_base('error message') if (Vote.find(:all, :conditions => {:post_id => post.id, :user_id => user.id} ).count > 0)
def something
errors.add_to_base(‘error message’) if user.votes.include?(self) # tu leży problem, gdy zmienię podaną wartość na Vote.first albo last waliduje prawidłowo
end
end[/code]
NoMethodError (You have a nil object when you didn't expect it!
The error occurred while evaluating nil.text?):
app/models/post.rb:20:in `vote'
Gdzie 20. linia to build.
validate_uniqueness_of :user, :scope => :post_id
end
class Post < ActiveRecord::Base
has_many :votes
def vote!(user)
votes.build(:user => user).save
end
end
w kontrolerze
@post = Post.find(params[:id])
if @post.vote!(current_user)
flasz
else
flasz…
end[/code]
[/quote]
Kilka drobnych uwag:
To nie idzie w transakcji, nie ma blokowania… więc spokojnie będzie można zagłosować kilka razy. 10 wątków odczyta jednocześnie dane… stwierdzi, że nie ma głosu i potem zagłosuje. Jedyne rozwiązanie: zrobienie porządnie bazy danych (dodanie unique(user, post) dzięki czemu kolejne inserty się wywalą) oraz obsługa tego, że insert się nie uda w modelu żeby powiadomić użytkownika.
Coś mi świta, że zgodnie z konwencją Rubiego funkcja vote! powinna być tylko specjalną wersją funkcji vote, a takiej nie ma.
Jedyną konwencją jaką znam w tym obszarze to, że ! używa się do oznaczania potencjalnie niebezpiecznych metod, rzucających wyjątek lub modyfikujących obiekt in-place (zamiast zwracania bezpiecznej kopii, patrz kolekcje).
W ogóle przydałby się dobry gem do głosowania, bo vote_fu niby działa, ale po instalacji trzeba zmienić kilka plików, nie mówiąc już o późniejszym dostosowaniu tego pluginu do działania z postgresem…