Reputation: 446
Then it came the moment to implement some sort of achievement in our web application. I had an idea more or less like the hierarcy described in this question How to implement an achievement system in RoR .
The application we are working on is a software as a service intended to be managed externally without software developers. The thing is it should be possible to create new kinds of achievements runtime by the software administrator via the web interface. The hierarcy then becomes a wall.
I have read somewhere it is possible to implement this situation through finite state machines, but at this time i don't have enough informations about that topic.
Edit: specific question
I thought about modeling an achievement class with a list of conditions to be met. This basic class Achievement would have a boolean which recursively checks all the conditions to be valid. The conditions then could be hardcoded classes. The system admin then creates new kind of achievements with combinations of the atomic conditions.
My fear is the growing number of classes for the atomic conditions. I dont want to have 30+ condition classes in the project. Any advise is really appreciated.
Edit: more details about the implementation
From SpyrosP response, it seems a good idea to build the described DSL. In some way achievements then must be saved in the database. Keeping the same example:
comments :less_than => 10
check_comments
comments :more_or_equal => 100
award_hundred_comments_badge
In order to dinamically create achievements there should be a table that stores the condition(s) to be checked:
Achievement
| id | name |
| 1 | "Houndred Comments" |
Condition
| achievement_id | expression |
| 1 | some sort of condition |
Upvotes: 2
Views: 458
Reputation: 48686
I've been interested in the same idea and was reading different stuff some time ago. Probably the best way to do such a thing is by using observers. An observer is like a standard filter(before_filter and the likes), but with some differences, like how the return value is handled and so on.
That said, if your system is really really complex, you may want to use a state machine plugin like https://github.com/pluginaweek/state_machine . However, i feel that this is too much for an Achievements functionality.
If i had to face complex Achiement scenarios, i would probably create a simple DSL that defines the behavior of an achievement. Something like :
for_achievement :hundred_comments do
before_achievement :status => Comment, :lower_than => 100
after_achievement :status => Comment, :more_or_equals => 100
end
You get the idea. This would be a way to fully describe an achievement. Your observers would then be able to use your achievement.rb class scenarios, in order to make out whether an achievement was reached. Think of it the way CanCan works. This could also be a nice way for your administrators to write simple achievement requirements through an even simpler DSL than what i presented in my example above.
Hope that helps a bit, or at least gives you some ideas :)
EDIT : Simpler DSL
A DSL can be really simple and expressive, so that people may even like to write scenarios with. Something like :
comments :less_than => 10
check_comments
comments :more_or_equal => 100
award_hundred_comments_badge
This can easily be formed to be a valid scenario of achieving 100 comments. Let's think of a scenario where the user gets a badge if he has invited exactly 10 people who are women in gender.
invites :less_than => 10, gender :female
check_invites
invites :equals => 10, gender :female
award_women_invitations_badge
Now, i think that this is very simple to write even for admins who have no clue about ruby, if you explain to them basic stuff about the DSL. But if you do not want them to go into that, you can create a form like :
Action Dropdown => [Comment, Invite, Post, ....]
Condition => [Equal, Less Than, More Than, ....]
Condition_Value => (TextBox to write value to)
CheckCondition => [Check Invitation Count, Check Messages Count, ....]
Upvotes: 1