Nie bardzo wiem jak się zabrać za takie coś.
Mam modele User, Entry i EntryVote. User może głosować na Entry, wtedy dodawany jest do tabeli entry_votes rekord user_id, entry_id.
W widoku dla entries#show wyświetlam przyciski do głosowania w których wysyłam entry_id jako parametr. No i teraz chcę ustawić, że użytkownik:
can :create, EntryVote
i cannot :create, EntryVote jeżeli jest już rekord z user_id i entry_id
Będę wdzięczny za jakieś podpowiedzi jak tego ‘cannot’ zrobić.
Pomyślałem, że jakoś tak zgrabniej będzie jak w widoku dam tylko jednego ifa coś w stylu:
<% if can? :create, EntryVote.new(user_id: current_user.id, entry_id: @entry.id) %>
<a href="#">+1</a>
<% else %>
<span>+1</span>
<% end %>
Zamiast if can? i dodatkowo sprawdzenie czy nie ma takich rekordow.
Arnvald mówi o walidacji na poziomie modelu, nic nie musisz (ba, nawet nie powinieneś) robić w widoku. Walidacja następuje przed zapisem i w kontrolerze już obsługujesz sobie przypadek jakby się nie zapisało.
Teraz to już raczej kwestie estetyczne, jak podsuneliscie mi pomysl jak to zrobic inaczej. Więc teraz czysto teoretycznie :), gdybym takie coś chciał zrobić w ability cancana, to jak sie do tego zabrac?
CanCan działa tak ze sprawdza czy dany warunek ma true lub false, masz tam dostep do obiektu ktory przekazujesz, usera, i polaczonych rzeczy, mozesz tam dac blok i zwrocic ture false dla warnku i tyle
Powiedzcie czy dobrze myślę. CanCan działa jak taki rozbudowany before_filter. Przez to, w modelu ability nie mam dostępu do zmiennych z kontrolera, bo te zmienne nie zostały jeszcze zainicjalizowane (chyba ze dodam load_resources). Powinienem mieć za to dostęp do zmiennej params.
Próbuję zrobić coś takiego (na podstawie tego co podrzucił sebcioz)
Przy linku na głosowanie uruchamiam EntryVotes#create z id entry w params[:id]
W ability cancana tworzę regułę:
cannot :create, EntryVote do |ev|
user.voted? Entry.find(params[:id])
end
niestety coś tu nie działa, CanCan rzuca mi wyjątek AccessDenied dla Entry gdzie uzytkownik nie glosował, czyli user.voted? daje false.
Po pierwsze, żeby params były dostępne w modelu Ability trzeba w application_controller.rb dodać:
[code=ruby]private
def current_ability @current_ability ||= Ability.new(current_user, params)
end[/code]
I odpowiednio zupdejtować wywołanie metody initialize modelu Ability:
def initialize(user, params)
W moim przypadku,w ustawieniu permissions dałem
unless !params[:id].nil? && user.voted?(Entry.find(params[:id]))
can :create, EntryVote
end
I wszystko śmiga tak jak chciałem.