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

Author: Danubian Sailor, 2009-05-20

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.

 52
Author: molf,
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!

 18
Author: Paul Campbell,
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 .

 7
Author: TuteC,
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