Jak wdrożyć system osiągnięć w RoR
Próbuję, słabo, zaimplementować system osiągnięć do mojej aplikacji Ruby on Rails.
Mam długą listę osiągnięć, które chciałbym sprawdzić. Wszystkie są wyzwalane przez niektóre akcje create w różnych kontrolerach.
Wpadłem na pomysł, że będę miał model osiągnięć, który zawiera kontroler i akcję, na którą reaguje. Następnie wykonaj filtr przed Dla Utwórz i sprawdź odpowiednie osiągnięcia. Utknąłem, jeśli chodzi o definiowanie / wykonywanie osiągnięcia. Każde osiągnięcie może wymagać innych danych. Na przykład jeden będzie chciał wiedzieć, ile pytań odpowiedział użytkownik, inny, ile komentarzy zrobił, a trzeci, ile osób użytkownik zaprosił odpowiedzi.
Czy najlepiej jest po prostu osadzić cały niezbędny kod ruby bezpośrednio w DB? Widzę, że robi samowystarczalny blok, który wykonuje wszystkie wyszukiwania rekordu aktywnego itp. i zwraca true / false, choć nadal mamy pewne problemy o tym, co jest ustawione z góry(tj. current_user, itp.).
Jakieś rozsądne najlepsze praktyki, które nie sprawiają, że czuję się brudny? Widziałem pełny silnik zasad / zasad będący jedną ścieżką, choć może mnie to bardziej przestraszyć niż plan A.
Dzięki! Oren
3 answers
Zgadzam się z Twoim pomysłem użycia modelu {[2] }.
Prawdopodobnie nie powinieneś implementować wyzwalaczy w kontrolerach. Wyobraź sobie, że masz dwa sposoby na napisanie komentarza; nieuchronnie otrzymasz duplikację kodu. Takie zachowanie należy do modelu.
Załóżmy, że chcesz śledzić liczbę komentarzy użytkownika i przyznać osiągnięcie za 100 komentarzy. Można mieć następujące modele:
class User < ActiveRecord::Base
has_many :comments
has_many :achievements
def award(achievement)
achievements << achievement.new
end
def awarded?(achievement)
achievements.count(:conditions => { :type => achievement }) > 0
end
end
class Achievement < ActiveRecord::Base
belongs_to :user
end
class Comment < ActiveRecord::Base
belongs_to :user
end
class CommentAchievement < Achievement
def self.check_conditions_for(user)
# Check if achievement is already awarded before doing possibly expensive
# operations to see if the achievement conditions are met.
if !user.awarded?(self) and user.comments.size > 100
user.award(self)
end
end
end
Różne osiągnięcia są podklasami z modelu Achievement
i używać dziedziczenia pojedynczej tabeli tak, aby były przechowywane tylko w jednej tabeli. Podklasy mogą zawierać całą logikę wymaganą dla każdego osiągnięcia. W tym modelu można również przechowywać dodatkowe informacje, takie jak data przyznania osiągnięcia. Aby upewnić się, że baza danych odrzuca duplikaty osiągnięć, możesz utworzyć indeks {[4] } na kolumnach type
i user_id
.
CommentAchievement.check_conditions_for(user)
można dzwonić, kiedy tylko chcesz. Możesz utworzyć zadanie w tle, które działa co jakiś czas, albo można utworzyć obserwatora:
# app/models/comment_achievement_observer.rb
class CommentAchievementObserver < ActiveRecord::Observer
observe :comment
def after_create(comment)
CommentAchievement.check_conditions_for(comment.user)
end
end
# config/environment.rb
config.active_record.observers = :comment_achievement_observer
Powyższe jest tylko jednym pomysłem, jak to zrobić, oczywiście mogą być inne. Kod to tylko przykład, nie testowałem go. Mam nadzieję, że to ci pomoże.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-19 08:51:26
Naprawdę ładne rozwiązanie, molf.
Wrzuciłem to do pluginu / gem z generatorami dla nowych osiągnięć:
Http://github.com/paulca/paths_of_glory
Szczęśliwego osiągnięcia!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-20 14:14:03
Napisałem do tego zadania klejnot Rails 3, który działa na odznaki, punkty i rankingi. Kod źródłowy znajdziesz w https://github.com/tute/merit .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-29 22:48:31