Skip to content
This repository
Browse code

Initial commit.

  • Loading branch information...
commit af349a02b7b7403a360d688bc3260fa3fd4c9c4e 0 parents
Tute Costa authored

Showing 73 changed files with 10,556 additions and 0 deletions. Show diff stats Hide diff stats

  1. +7 0 .gitignore
  2. +4 0 Gemfile
  3. +73 0 Gemfile.lock
  4. +26 0 README.rdoc
  5. +29 0 Rakefile
  6. +2 0  app/models/badge.rb
  7. +93 0 ideas.rb
  8. +26 0 lib/generators/talent/install_generator.rb
  9. +19 0 lib/generators/talent/templates/create_badges.rb
  10. +11 0 lib/generators/talent/templates/create_badges_users.rb
  11. +16 0 lib/generators/talent/templates/create_talent_actions.rb
  12. +7 0 lib/talent.rb
  13. +30 0 lib/talent/controller_additions.rb
  14. +7 0 lib/talent/railtie.rb
  15. +51 0 lib/talent/rules.rb
  16. +9 0 talent.gemspec
  17. +7 0 test/dummy/Rakefile
  18. +7 0 test/dummy/app/controllers/application_controller.rb
  19. +85 0 test/dummy/app/controllers/comments_controller.rb
  20. +85 0 test/dummy/app/controllers/users_controller.rb
  21. +2 0  test/dummy/app/helpers/application_helper.rb
  22. +3 0  test/dummy/app/models/badge.rb
  23. +3 0  test/dummy/app/models/comment.rb
  24. +2 0  test/dummy/app/models/talent_action.rb
  25. +17 0 test/dummy/app/models/talent_rules.rb
  26. +4 0 test/dummy/app/models/user.rb
  27. +29 0 test/dummy/app/views/comments/_form.html.erb
  28. +6 0 test/dummy/app/views/comments/edit.html.erb
  29. +27 0 test/dummy/app/views/comments/index.html.erb
  30. +5 0 test/dummy/app/views/comments/new.html.erb
  31. +20 0 test/dummy/app/views/comments/show.html.erb
  32. +14 0 test/dummy/app/views/layouts/application.html.erb
  33. +21 0 test/dummy/app/views/users/_form.html.erb
  34. +6 0 test/dummy/app/views/users/edit.html.erb
  35. +23 0 test/dummy/app/views/users/index.html.erb
  36. +5 0 test/dummy/app/views/users/new.html.erb
  37. +20 0 test/dummy/app/views/users/show.html.erb
  38. +4 0 test/dummy/config.ru
  39. +24 0 test/dummy/config/application.rb
  40. +10 0 test/dummy/config/boot.rb
  41. +22 0 test/dummy/config/database.yml
  42. +5 0 test/dummy/config/environment.rb
  43. +26 0 test/dummy/config/environments/development.rb
  44. +49 0 test/dummy/config/environments/production.rb
  45. +35 0 test/dummy/config/environments/test.rb
  46. +7 0 test/dummy/config/initializers/backtrace_silencers.rb
  47. +10 0 test/dummy/config/initializers/inflections.rb
  48. +5 0 test/dummy/config/initializers/mime_types.rb
  49. +7 0 test/dummy/config/initializers/secret_token.rb
  50. +8 0 test/dummy/config/initializers/session_store.rb
  51. +5 0 test/dummy/config/locales/en.yml
  52. +5 0 test/dummy/config/routes.rb
  53. +12 0 test/dummy/db/migrate/20110421191249_create_users.rb
  54. +15 0 test/dummy/db/migrate/20110421191250_create_comments.rb
  55. +53 0 test/dummy/db/schema.rb
  56. +16 0 test/dummy/db/seeds.rb
  57. +26 0 test/dummy/public/404.html
  58. +26 0 test/dummy/public/422.html
  59. +26 0 test/dummy/public/500.html
  60. 0  test/dummy/public/favicon.ico
  61. +2 0  test/dummy/public/javascripts/application.js
  62. +965 0 test/dummy/public/javascripts/controls.js
  63. +974 0 test/dummy/public/javascripts/dragdrop.js
  64. +1,123 0 test/dummy/public/javascripts/effects.js
  65. +6,001 0 test/dummy/public/javascripts/prototype.js
  66. +191 0 test/dummy/public/javascripts/rails.js
  67. 0  test/dummy/public/stylesheets/.gitkeep
  68. +56 0 test/dummy/public/stylesheets/scaffold.css
  69. +6 0 test/dummy/script/rails
  70. +7 0 test/integration/navigation_test.rb
  71. +5 0 test/support/integration_case.rb
  72. +7 0 test/talent_test.rb
  73. +22 0 test/test_helper.rb
7 .gitignore
... ... @@ -0,0 +1,7 @@
  1 +.DS_Store
  2 +.bundle/
  3 +log/*.log
  4 +pkg/
  5 +test/dummy/db/*.sqlite3
  6 +test/dummy/log/*.log
  7 +test/dummy/tmp/
4 Gemfile
... ... @@ -0,0 +1,4 @@
  1 +source "http://rubygems.org"
  2 +
  3 +gem "rails", "3.0.7"
  4 +gem "sqlite3"
73 Gemfile.lock
... ... @@ -0,0 +1,73 @@
  1 +GEM
  2 + remote: http://rubygems.org/
  3 + specs:
  4 + abstract (1.0.0)
  5 + actionmailer (3.0.7)
  6 + actionpack (= 3.0.7)
  7 + mail (~> 2.2.15)
  8 + actionpack (3.0.7)
  9 + activemodel (= 3.0.7)
  10 + activesupport (= 3.0.7)
  11 + builder (~> 2.1.2)
  12 + erubis (~> 2.6.6)
  13 + i18n (~> 0.5.0)
  14 + rack (~> 1.2.1)
  15 + rack-mount (~> 0.6.14)
  16 + rack-test (~> 0.5.7)
  17 + tzinfo (~> 0.3.23)
  18 + activemodel (3.0.7)
  19 + activesupport (= 3.0.7)
  20 + builder (~> 2.1.2)
  21 + i18n (~> 0.5.0)
  22 + activerecord (3.0.7)
  23 + activemodel (= 3.0.7)
  24 + activesupport (= 3.0.7)
  25 + arel (~> 2.0.2)
  26 + tzinfo (~> 0.3.23)
  27 + activeresource (3.0.7)
  28 + activemodel (= 3.0.7)
  29 + activesupport (= 3.0.7)
  30 + activesupport (3.0.7)
  31 + arel (2.0.9)
  32 + builder (2.1.2)
  33 + erubis (2.6.6)
  34 + abstract (>= 1.0.0)
  35 + i18n (0.5.0)
  36 + mail (2.2.17)
  37 + activesupport (>= 2.3.6)
  38 + i18n (>= 0.4.0)
  39 + mime-types (~> 1.16)
  40 + treetop (~> 1.4.8)
  41 + mime-types (1.16)
  42 + polyglot (0.3.1)
  43 + rack (1.2.2)
  44 + rack-mount (0.6.14)
  45 + rack (>= 1.0.0)
  46 + rack-test (0.5.7)
  47 + rack (>= 1.0)
  48 + rails (3.0.7)
  49 + actionmailer (= 3.0.7)
  50 + actionpack (= 3.0.7)
  51 + activerecord (= 3.0.7)
  52 + activeresource (= 3.0.7)
  53 + activesupport (= 3.0.7)
  54 + bundler (~> 1.0)
  55 + railties (= 3.0.7)
  56 + railties (3.0.7)
  57 + actionpack (= 3.0.7)
  58 + activesupport (= 3.0.7)
  59 + rake (>= 0.8.7)
  60 + thor (~> 0.14.4)
  61 + rake (0.8.7)
  62 + sqlite3 (1.3.3)
  63 + thor (0.14.6)
  64 + treetop (1.4.9)
  65 + polyglot (>= 0.3.1)
  66 + tzinfo (0.3.26)
  67 +
  68 +PLATFORMS
  69 + ruby
  70 +
  71 +DEPENDENCIES
  72 + rails (= 3.0.7)
  73 + sqlite3
26 README.rdoc
Source Rendered
... ... @@ -0,0 +1,26 @@
  1 += Talent
  2 +
  3 +== Installation
  4 +
  5 +# Add 'talent' to your Gemfile.
  6 +# Run 'rails g badges:install'
  7 +# Add 'grant_badges' to controllers where you want this behavior triggered.
  8 +# Run 'rake db:migrate'
  9 +
  10 +
  11 +== Test application
  12 +
  13 +To run the test application inside this gem follow:
  14 +
  15 +# cd test/dummy
  16 +# rails g talent:install
  17 +# rake db:drop ; rake db:create ; rake db:migrate ; rake db:seed
  18 +# rails s
  19 +
  20 +
  21 +== To-do list
  22 +
  23 +* Persistir last_action_checked (se resetea!).
  24 +* Add has_and_belongs_to_many :badges to related models.
  25 +* Add talent_action model?
  26 +* Migration should accept any model (not just 'user').
29 Rakefile
... ... @@ -0,0 +1,29 @@
  1 +# encoding: UTF-8
  2 +require 'rubygems'
  3 +begin
  4 + require 'bundler/setup'
  5 +rescue LoadError
  6 + puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
  7 +end
  8 +
  9 +require 'rake'
  10 +require 'rake/rdoctask'
  11 +
  12 +require 'rake/testtask'
  13 +
  14 +Rake::TestTask.new(:test) do |t|
  15 + t.libs << 'lib'
  16 + t.libs << 'test'
  17 + t.pattern = 'test/**/*_test.rb'
  18 + t.verbose = false
  19 +end
  20 +
  21 +task :default => :test
  22 +
  23 +Rake::RDocTask.new(:rdoc) do |rdoc|
  24 + rdoc.rdoc_dir = 'rdoc'
  25 + rdoc.title = 'Talent'
  26 + rdoc.options << '--line-numbers' << '--inline-source'
  27 + rdoc.rdoc_files.include('README.rdoc')
  28 + rdoc.rdoc_files.include('lib/**/*.rb')
  29 +end
2  app/models/badge.rb
... ... @@ -0,0 +1,2 @@
  1 +class Badge < ActiveRecord::Base
  2 +end
93 ideas.rb
... ... @@ -0,0 +1,93 @@
  1 +# 1- Ir llenando una tabla "acciones" del estilo de:
  2 +# _______________________________________________
  3 +# source (user_id) | action (method, value) | target (model, id)
  4 +# 1 | comment nil | List 8
  5 +# 1 | vote 3 | List 12
  6 +# 3 | follow nil | User 1
  7 +# X | create nil | User nil # se registra un usuario, X es el id generado
  8 +# _______________________________________________
  9 +#
  10 +# Se define las acciones a trackear en los controladores, por ejemplo:
  11 +# class UsersController < ApplicationController
  12 +# grant_badges :only => %w(create follow)
  13 +# end
  14 +#
  15 +# La gema también crearía una tabla Badges, más o menos como sigue:
  16 +# ___________________
  17 +# id | name | level | image
  18 +# 1 | creador | inspirado | creador-inspirado.png
  19 +# 2 | creador | blogger | creador-blogger.png
  20 +# 2 | creador | best-seller | creador-bestseller.png
  21 +# ___________________
  22 +#
  23 +#
  24 +# 2- La interfaz para especificar desde la aplicación cuándo aplicar cada badge
  25 +# sería un archivo tipo el ability.rb de cancan, que estaría en
  26 +# app/models/talent.rb, con una sintaxis tipo:
  27 +#
  28 +# grant_on 'users#create', :badge => 'just', :level => 'registered' do
  29 +# # Code block
  30 +# end
  31 +#
  32 +# Donde el procedimiento es un método que chequea la lógica necesaria para dar
  33 +# ese badge, y evalúa a boolean. Obviamente tiene que saber de qué objetos
  34 +# estamos hablando (qué user y qué lista, por ejemplo), cabo que por ahora no
  35 +# queda atado.
  36 +#
  37 +#
  38 +# 3- Luego, podemos ir chequeando esas condiciones sincronizadamente, o
  39 +# mediante un proceso en background, por ejemplo cada 5 minutos, guardando
  40 +# hasta qué entrada de la primera tabla se procesó la vez anterior.
  41 +
  42 +
  43 +# ========== Posible sintaxis ==========
  44 +
  45 +# app/models/talent.rb (onda cancan)
  46 +class Talent
  47 + include Talent::Badges
  48 +
  49 + def initialize(user)
  50 + user ||= User.new
  51 +
  52 + grant_on 'users#create', :badge => 'just', :level => 'registered' do
  53 + true
  54 + end
  55 +
  56 + grant_on 'comments#create', :badge => 'commenter', :level => 10 do
  57 + current_user.comments.count == 10
  58 + end
  59 + end
  60 +end
  61 +
  62 +# app/controllers/users_controller.rb
  63 +class UsersController < ApplicationController
  64 + grant_badges :only => %w(index create edit)
  65 +end
  66 +
  67 +
  68 +# ========== Tests ==========
  69 +u = User.first
  70 +u.badges
  71 +c = Comment.new{ :user_id = u.id }
  72 +c.save
  73 +u.badges
  74 +
  75 +u = User.first
  76 +u.badges
  77 +TalentRules.new(u) # Not loading all rules (?)
  78 +include Talent::Rules
  79 +check_last_actions
  80 +u.badges
  81 +
  82 +
  83 +# ========== URLs ==========
  84 +# http://www.cowboycoded.com/2011/01/31/developing-is_able-or-acts_as-plugins-for-rails/
  85 +# http://www.stubbleblog.com/index.php/2011/04/writing-rails-engines-getting-started/
  86 +# https://gist.github.com/af7e572c2dc973add221
  87 +# http://www.themodestrubyist.com/2010/03/01/rails-3-plugins---part-1---the-big-picture/
  88 +# http://www.themodestrubyist.com/2010/03/05/rails-3-plugins---part-2---writing-an-engine/
  89 +# http://www.themodestrubyist.com/2010/03/16/rails-3-plugins---part-3---rake-tasks-generators-initializers-oh-my/
  90 +# https://github.com/krschacht/rails_3_engine_demo
  91 +
  92 +https://github.com/dcadenas/state_pattern
  93 +https://github.com/rubyist/aasm
26 lib/generators/talent/install_generator.rb
... ... @@ -0,0 +1,26 @@
  1 +require 'rails/generators/migration'
  2 +
  3 +module Talent
  4 + module Generators
  5 + class InstallGenerator < ::Rails::Generators::Base
  6 + include Rails::Generators::Migration
  7 + source_root File.expand_path('../templates', __FILE__)
  8 + desc "add the migrations"
  9 +
  10 + def self.next_migration_number(path)
  11 + unless @prev_migration_nr
  12 + @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
  13 + else
  14 + @prev_migration_nr += 1
  15 + end
  16 + @prev_migration_nr.to_s
  17 + end
  18 +
  19 + def copy_migrations
  20 + migration_template 'create_talent_actions.rb', 'db/migrate/create_talent_actions.rb'
  21 + migration_template 'create_badges.rb', 'db/migrate/create_badges.rb'
  22 + migration_template 'create_badges_users.rb', 'db/migrate/create_badges_users.rb'
  23 + end
  24 + end
  25 + end
  26 +end
19 lib/generators/talent/templates/create_badges.rb
... ... @@ -0,0 +1,19 @@
  1 +class CreateBadges < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :badges do |t|
  4 + t.string :name
  5 + t.string :level
  6 + t.string :image
  7 + t.string :description
  8 + t.timestamps
  9 + end
  10 +
  11 + # First badge
  12 + Badge.create( :name => 'just', :level => 'registered' ) # just-did-something
  13 + Badge.create( :name => 'creator', :level => 'inspired', :image => 'http://upload.wikimedia.org/wikipedia/commons/9/94/Luca_prodan.jpg' )
  14 + end
  15 +
  16 + def self.down
  17 + drop_table :badges
  18 + end
  19 +end
11 lib/generators/talent/templates/create_badges_users.rb
... ... @@ -0,0 +1,11 @@
  1 +class CreateBadgesUsers < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :badges_users, :id => false do |t|
  4 + t.integer :badge_id, :user_id
  5 + end
  6 + end
  7 +
  8 + def self.down
  9 + drop_table :badges_users
  10 + end
  11 +end
16 lib/generators/talent/templates/create_talent_actions.rb
... ... @@ -0,0 +1,16 @@
  1 +class CreateTalentActions < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :talent_actions do |t|
  4 + t.integer :user_id # source
  5 + t.string :action_method
  6 + t.integer :action_value
  7 + t.string :target_model
  8 + t.integer :target_id
  9 + t.timestamps
  10 + end
  11 + end
  12 +
  13 + def self.down
  14 + drop_table :talent_actions
  15 + end
  16 +end
7 lib/talent.rb
... ... @@ -0,0 +1,7 @@
  1 +require 'talent/controller_additions'
  2 +require 'talent/rules'
  3 +
  4 +module Talent
  5 + class Engine < Rails::Engine
  6 + end
  7 +end
30 lib/talent/controller_additions.rb
... ... @@ -0,0 +1,30 @@
  1 +module Talent
  2 + # This module is automatically included into all controllers.
  3 + module ControllerMethods
  4 + # Sets up a before filter to update talent_actions table
  5 + #
  6 + # class UsersController < ApplicationController
  7 + # grant_badges :only => %w(create follow)
  8 + # end
  9 + #
  10 + def grant_badges(*args)
  11 + # Initialize rules
  12 + ::TalentRules.new(current_user) # FIXME: debería ser Singleton?
  13 +
  14 + options = args.extract_options!
  15 + self.before_filter(options) do |controller|
  16 + TalentAction.create(
  17 + :user_id => ApplicationController.current_user.try(:id),
  18 + :action_method => action_name,
  19 + :action_value => nil, # FIXME: Aún no implementado
  20 + :target_model => controller.controller_name,
  21 + :target_id => controller.params[:id]
  22 + )
  23 + end
  24 + end
  25 + end
  26 +end
  27 +
  28 +if defined? ActionController
  29 + ActionController::Base.extend Talent::ControllerMethods
  30 +end
7 lib/talent/railtie.rb
... ... @@ -0,0 +1,7 @@
  1 +require 'talent'
  2 +require 'rails'
  3 +
  4 +module Talent
  5 + class Engine < Rails::Engine
  6 + end
  7 +end
51 lib/talent/rules.rb
... ... @@ -0,0 +1,51 @@
  1 +module Talent
  2 + module Rules
  3 + # Grant badge to user if applies
  4 + def grant_on(action, *args, &block)
  5 + options = args.extract_options!
  6 + talent_rules[action] ||= []
  7 + talent_rules[action] << {
  8 + :badge => options[:badge],
  9 + :level => options[:level],
  10 + :block => block
  11 + }
  12 + Rails.logger.warn "TALENT: Added rule for #{action}."
  13 + end
  14 +
  15 + def check_last_actions
  16 + last_id = TalentAction.last.id
  17 + # FIXME: where(:id => [last_action_checked..last_id])
  18 + # "Arel error: Can't visit range". Why isn't it working with range?
  19 + TalentAction.where("#{last_action_checked} < id AND id <= #{last_id}").each do |action|
  20 + check_rules(action)
  21 + end
  22 + last_action_checked = last_id
  23 + end
  24 +
  25 + def check_rules(action)
  26 + action_name = "#{action.target_model}\##{action.action_method}"
  27 + talent_rules[action_name].each do |rule|
  28 + Rails.logger.warn "TALENT: Checking #{talent_rules[action_name].count} rules for #{action_name}..."
  29 + user = User.find(action.user_id)
  30 + badge = Badge.where(:name => rule[:badge], :level => rule[:level]).first
  31 + if rule[:block].call && !user.badges.include?(badge)
  32 + user.badges << badge
  33 + user.save
  34 + Rails.logger.warn "TALENT: Granted badge #{badge.name}-#{badge.level} to #{user.name}!"
  35 + end
  36 + end unless talent_rules[action_name].nil?
  37 + end
  38 +
  39 + def talent_rules
  40 + @talent_rules ||= {}
  41 + end
  42 +
  43 + def last_action_checked
  44 + @last_action_checked ||= 0
  45 + end
  46 +
  47 + def last_action_checked=(last_id)
  48 + @last_action_checked = last_id
  49 + end
  50 + end
  51 +end
9 talent.gemspec
... ... @@ -0,0 +1,9 @@
  1 +# Provide a simple gemspec so you can easily use your enginex
  2 +# project in your rails apps through git.
  3 +Gem::Specification.new do |s|
  4 + s.name = "talent"
  5 + s.summary = "Badges Rails engine."
  6 + s.description = "Badges Rails engine."
  7 + s.files = Dir["{app,lib,config}/**/*"] + ["MIT-LICENSE", "Rakefile", "Gemfile", "README.rdoc"]
  8 + s.version = "0.0.1"
  9 +end
7 test/dummy/Rakefile
... ... @@ -0,0 +1,7 @@
  1 +# Add your own tasks in files placed in lib/tasks ending in .rake,
  2 +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
  3 +
  4 +require File.expand_path('../config/application', __FILE__)
  5 +require 'rake'
  6 +
  7 +Dummy::Application.load_tasks
7 test/dummy/app/controllers/application_controller.rb
... ... @@ -0,0 +1,7 @@
  1 +class ApplicationController < ActionController::Base
  2 + protect_from_forgery
  3 +
  4 + def self.current_user
  5 + @current_user ||= User.find 1
  6 + end
  7 +end
85 test/dummy/app/controllers/comments_controller.rb
... ... @@ -0,0 +1,85 @@
  1 +class CommentsController < ApplicationController
  2 + grant_badges :only => %w(create)
  3 +
  4 + # GET /comments
  5 + # GET /comments.xml
  6 + def index
  7 + @comments = Comment.all
  8 +
  9 + respond_to do |format|
  10 + format.html # index.html.erb
  11 + format.xml { render :xml => @comments }
  12 + end
  13 + end
  14 +
  15 + # GET /comments/1
  16 + # GET /comments/1.xml
  17 + def show
  18 + @comment = Comment.find(params[:id])
  19 +
  20 + respond_to do |format|
  21 + format.html # show.html.erb
  22 + format.xml { render :xml => @comment }
  23 + end
  24 + end
  25 +
  26 + # GET /comments/new
  27 + # GET /comments/new.xml
  28 + def new
  29 + @comment = Comment.new
  30 +
  31 + respond_to do |format|
  32 + format.html # new.html.erb
  33 + format.xml { render :xml => @comment }
  34 + end
  35 + end
  36 +
  37 + # GET /comments/1/edit
  38 + def edit
  39 + @comment = Comment.find(params[:id])
  40 + end
  41 +
  42 + # POST /comments
  43 + # POST /comments.xml
  44 + def create
  45 + @comment = Comment.new(params[:comment])
  46 +
  47 + respond_to do |format|
  48 + if @comment.save
  49 + format.html { redirect_to(@comment, :notice => 'Comment was successfully created.') }
  50 + format.xml { render :xml => @comment, :status => :created, :location => @comment }
  51 + else
  52 + format.html { render :action => "new" }
  53 + format.xml { render :xml => @comment.errors, :status => :unprocessable_entity }
  54 + end
  55 + end
  56 + end
  57 +
  58 + # PUT /comments/1
  59 + # PUT /comments/1.xml
  60 + def update
  61 + @comment = Comment.find(params[:id])
  62 +
  63 + respond_to do |format|
  64 + if @comment.update_attributes(params[:comment])
  65 + format.html { redirect_to(@comment, :notice => 'Comment was successfully updated.') }
  66 + format.xml { head :ok }
  67 + else
  68 + format.html { render :action => "edit" }
  69 + format.xml { render :xml => @comment.errors, :status => :unprocessable_entity }
  70 + end
  71 + end
  72 + end
  73 +
  74 + # DELETE /comments/1
  75 + # DELETE /comments/1.xml
  76 + def destroy
  77 + @comment = Comment.find(params[:id])
  78 + @comment.destroy
  79 +
  80 + respond_to do |format|
  81 + format.html { redirect_to(comments_url) }
  82 + format.xml { head :ok }
  83 + end
  84 + end
  85 +end
85 test/dummy/app/controllers/users_controller.rb
... ... @@ -0,0 +1,85 @@
  1 +class UsersController < ApplicationController
  2 + grant_badges :only => %w(index create edit)
  3 +
  4 + # GET /users
  5 + # GET /users.xml
  6 + def index
  7 + @users = User.all
  8 +
  9 + respond_to do |format|
  10 + format.html # index.html.erb
  11 + format.xml { render :xml => @users }
  12 + end
  13 + end
  14 +
  15 + # GET /users/1
  16 + # GET /users/1.xml
  17 + def show
  18 + @user = User.find(params[:id])
  19 +
  20 + respond_to do |format|
  21 + format.html # show.html.erb
  22 + format.xml { render :xml => @user }
  23 + end
  24 + end
  25 +
  26 + # GET /users/new
  27 + # GET /users/new.xml
  28 + def new
  29 + @user = User.new
  30 +
  31 + respond_to do |format|
  32 + format.html # new.html.erb
  33 + format.xml { render :xml => @user }
  34 + end
  35 + end
  36 +
  37 + # GET /users/1/edit
  38 + def edit
  39 + @user = User.find(params[:id])
  40 + end
  41 +
  42 + # POST /users
  43 + # POST /users.xml
  44 + def create
  45 + @user = User.new(params[:user])
  46 +
  47 + respond_to do |format|
  48 + if @user.save
  49 + format.html { redirect_to(@user, :notice => 'User was successfully created.') }
  50 + format.xml { render :xml => @user, :status => :created, :location => @user }
  51 + else
  52 + format.html { render :action => "new" }
  53 + format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
  54 + end
  55 + end
  56 + end
  57 +
  58 + # PUT /users/1
  59 + # PUT /users/1.xml
  60 + def update
  61 + @user = User.find(params[:id])
  62 +
  63 + respond_to do |format|
  64 + if @user.update_attributes(params[:user])
  65 + format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
  66 + format.xml { head :ok }
  67 + else
  68 + format.html { render :action => "edit" }
  69 + format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
  70 + end
  71 + end
  72 + end
  73 +
  74 + # DELETE /users/1
  75 + # DELETE /users/1.xml
  76 + def destroy
  77 + @user = User.find(params[:id])
  78 + @user.destroy
  79 +
  80 + respond_to do |format|
  81 + format.html { redirect_to(users_url) }
  82 + format.xml { head :ok }
  83 + end
  84 + end
  85 +end
2  test/dummy/app/helpers/application_helper.rb
... ... @@ -0,0 +1,2 @@
  1 +module ApplicationHelper
  2 +end
3  test/dummy/app/models/badge.rb
... ... @@ -0,0 +1,3 @@
  1 +class Badge < ActiveRecord::Base
  2 + has_and_belongs_to_many :users
  3 +end
3  test/dummy/app/models/comment.rb
... ... @@ -0,0 +1,3 @@
  1 +class Comment < ActiveRecord::Base
  2 + belongs_to :user
  3 +end
2  test/dummy/app/models/talent_action.rb
... ... @@ -0,0 +1,2 @@
  1 +class TalentAction < ActiveRecord::Base
  2 +end
17 test/dummy/app/models/talent_rules.rb
... ... @@ -0,0 +1,17 @@
  1 +class TalentRules
  2 + include Talent::Rules
  3 +
  4 + def initialize(user)
  5 + user ||= User.new
  6 +
  7 + grant_on 'users#create', :badge => 'just', :level => 'registered' do
  8 + true
  9 + end
  10 +
  11 + grant_on 'comments#create', :badge => 'commenter', :level => 10 do
  12 + user.comments.count == 10
  13 + end
  14 +
  15 + check_last_actions # FIXME: Should be called every 5 mins or every action, but not from here.
  16 + end
  17 +end
4 test/dummy/app/models/user.rb
... ... @@ -0,0 +1,4 @@
  1 +class User < ActiveRecord::Base
  2 + has_many :comments
  3 + has_and_belongs_to_many :badges
  4 +end
29 test/dummy/app/views/comments/_form.html.erb
... ... @@ -0,0 +1,29 @@
  1 +<%= form_for(@comment) do |f| %>
  2 + <% if @comment.errors.any? %>
  3 + <div id="error_explanation">
  4 + <h2><%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
  5 +
  6 + <ul>
  7 + <% @comment.errors.full_messages.each do |msg| %>
  8 + <li><%= msg %></li>
  9 + <% end %>
  10 + </ul>
  11 + </div>
  12 + <% end %>
  13 +
  14 + <div class="field">
  15 + <%= f.label :name %><br />
  16 + <%= f.text_field :name %>
  17 + </div>
  18 + <div class="field">
  19 + <%= f.label :comment %><br />
  20 + <%= f.text_area :comment %>
  21 + </div>
  22 + <div class="field">
  23 + <%= f.label :user_id %><br />
  24 + <%= f.text_field :user_id %>
  25 + </div>
  26 + <div class="actions">
  27 + <%= f.submit %>
  28 + </div>
  29 +<% end %>
6 test/dummy/app/views/comments/edit.html.erb
... ... @@ -0,0 +1,6 @@
  1 +<h1>Editing comment</h1>
  2 +
  3 +<%= render 'form' %>
  4 +
  5 +<%= link_to 'Show', @comment %> |
  6 +<%= link_to 'Back', comments_path %>
27 test/dummy/app/views/comments/index.html.erb
... ... @@ -0,0 +1,27 @@
  1 +<h1>Listing comments</h1>
  2 +
  3 +<table>
  4 + <tr>
  5 + <th>Name</th>
  6 + <th>Comment</th>
  7 + <th>User</th>
  8 + <th></th>
  9 + <th></th>
  10 + <th></th>
  11 + </tr>
  12 +
  13 +<% @comments.each do |comment| %>
  14 + <tr>
  15 + <td><%= comment.name %></td>
  16 + <td><%= comment.comment %></td>
  17 + <td><%= comment.user_id %></td>
  18 + <td><%= link_to 'Show', comment %></td>
  19 + <td><%= link_to 'Edit', edit_comment_path(comment) %></td>
  20 + <td><%= link_to 'Destroy', comment, :confirm => 'Are you sure?', :method => :delete %></td>
  21 + </tr>
  22 +<% end %>
  23 +</table>
  24 +
  25 +<br />
  26 +
  27 +<%= link_to 'New Comment', new_comment_path %>
5 test/dummy/app/views/comments/new.html.erb
... ... @@ -0,0 +1,5 @@
  1 +<h1>New comment</h1>
  2 +
  3 +<%= render 'form' %>
  4 +
  5 +<%= link_to 'Back', comments_path %>
20 test/dummy/app/views/comments/show.html.erb
... ... @@ -0,0 +1,20 @@
  1 +<p id="notice"><%= notice %></p>
  2 +
  3 +<p>
  4 + <b>Name:</b>
  5 + <%= @comment.name %>
  6 +</p>
  7 +
  8 +<p>
  9 + <b>Comment:</b>
  10 + <%= @comment.comment %>
  11 +</p>
  12 +
  13 +<p>
  14 + <b>User:</b>
  15 + <%= @comment.user_id %>
  16 +</p>
  17 +
  18 +
  19 +<%= link_to 'Edit', edit_comment_path(@comment) %> |
  20 +<%= link_to 'Back', comments_path %>
14 test/dummy/app/views/layouts/application.html.erb
... ... @@ -0,0 +1,14 @@
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <title>Dummy</title>
  5 + <%= stylesheet_link_tag :all %>
  6 + <%= javascript_include_tag :defaults %>
  7 + <%= csrf_meta_tag %>
  8 +</head>
  9 +<body>
  10 +
  11 +<%= yield %>
  12 +
  13 +</body>
  14 +</html>
21 test/dummy/app/views/users/_form.html.erb
... ... @@ -0,0 +1,21 @@
  1 +<%= form_for(@user) do |f| %>
  2 + <% if @user.errors.any? %>
  3 + <div id="error_explanation">
  4 + <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
  5 +
  6 + <ul>
  7 + <% @user.errors.full_messages.each do |msg| %>
  8 + <li><%= msg %></li>
  9 + <% end %>
  10 + </ul>
  11 + </div>
  12 + <% end %>
  13 +
  14 + <div class="field">
  15 + <%= f.label :name %><br />
  16 + <%= f.text_field :name %>
  17 + </div>
  18 + <div class="actions">
  19 + <%= f.submit %>
  20 + </div>
  21 +<% end %>
6 test/dummy/app/views/users/edit.html.erb
... ... @@ -0,0 +1,6 @@
  1 +<h1>Editing user</h1>
  2 +
  3 +<%= render 'form' %>
  4 +
  5 +<%= link_to 'Show', @user %> |
  6 +<%= link_to 'Back', users_path %>
23 test/dummy/app/views/users/index.html.erb
... ... @@ -0,0 +1,23 @@
  1 +<h1>Listing users</h1>
  2 +
  3 +<table>
  4 + <tr>
  5 + <th>Name</th>
  6 + <th></th>
  7 + <th></th>
  8 + <th></th>
  9 + </tr>
  10 +
  11 +<% @users.each do |user| %>
  12 + <tr>
  13 + <td><%= user.name %></td>
  14 + <td><%= link_to 'Show', user %></td>
  15 + <td><%= link_to 'Edit', edit_user_path(user) %></td>
  16 + <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %></td>
  17 + </tr>
  18 +<% end %>
  19 +</table>
  20 +
  21 +<br />
  22 +
  23 +<%= link_to 'New User', new_user_path %>
5 test/dummy/app/views/users/new.html.erb
... ... @@ -0,0 +1,5 @@
  1 +<h1>New user</h1>
  2 +
  3 +<%= render 'form' %>
  4 +
  5 +<%= link_to 'Back', users_path %>
20 test/dummy/app/views/users/show.html.erb
... ... @@ -0,0 +1,20 @@
  1 +<p id="notice"><%= notice %></p>
  2 +
  3 +<p>
  4 + <b>Name:</b>
  5 + <%= @user.name %>
  6 +</p>
  7 +
  8 +<p>
  9 + <b>Comments:</b>
  10 + <%= @user.comments.count %>
  11 +</p>
  12 +
  13 +<p>
  14 + <b>Badges:</b>
  15 + <%= @user.badges.collect{|b| b.name.capitalize }.join(', ') %>
  16 +</p>
  17 +
  18 +
  19 +<%= link_to 'Edit', edit_user_path(@user) %> |
  20 +<%= link_to 'Back', users_path %>
4 test/dummy/config.ru
... ... @@ -0,0 +1,4 @@
  1 +# This file is used by Rack-based servers to start the application.
  2 +
  3 +require ::File.expand_path('../config/environment', __FILE__)
  4 +run Dummy::Application
24 test/dummy/config/application.rb
... ... @@ -0,0 +1,24 @@
  1 +require File.expand_path('../boot', __FILE__)
  2 +
  3 +require "active_model/railtie"
  4 +require "active_record/railtie"
  5 +require "action_controller/railtie"
  6 +require "action_view/railtie"
  7 +require "action_mailer/railtie"
  8 +
  9 +Bundler.require
  10 +require "talent"
  11 +
  12 +module Dummy
  13 + class Application < Rails::Application
  14 + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
  15 + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
  16 + # config.i18n.default_locale = :de
  17 +
  18 + # Configure the default encoding used in templates for Ruby 1.9.
  19 + config.encoding = "utf-8"
  20 +
  21 + # Configure sensitive parameters which will be filtered from the log file.
  22 + config.filter_parameters += [:password]
  23 + end
  24 +end
10 test/dummy/config/boot.rb
... ... @@ -0,0 +1,10 @@
  1 +require 'rubygems'
  2 +gemfile = File.expand_path('../../../../Gemfile', __FILE__)
  3 +
  4 +if File.exist?(gemfile)
  5 + ENV['BUNDLE_GEMFILE'] = gemfile
  6 + require 'bundler'
  7 + Bundler.setup
  8 +end
  9 +
  10 +$:.unshift File.expand_path('../../../../lib', __FILE__)
22 test/dummy/config/database.yml
... ... @@ -0,0 +1,22 @@
  1 +# SQLite version 3.x
  2 +# gem install sqlite3
  3 +development:
  4 + adapter: sqlite3
  5 + database: db/development.sqlite3
  6 + pool: 5
  7 + timeout: 5000
  8 +
  9 +# Warning: The database defined as "test" will be erased and
  10 +# re-generated from your development database when you run "rake".
  11 +# Do not set this db to the same as development or production.
  12 +test:
  13 + adapter: sqlite3
  14 + database: db/test.sqlite3
  15 + pool: 5
  16 + timeout: 5000
  17 +
  18 +production:
  19 + adapter: sqlite3
  20 + database: db/production.sqlite3
  21 + pool: 5
  22 + timeout: 5000
5 test/dummy/config/environment.rb
... ... @@ -0,0 +1,5 @@
  1 +# Load the rails application
  2 +require File.expand_path('../application', __FILE__)
  3 +
  4 +# Initialize the rails application
  5 +Dummy::Application.initialize!
26 test/dummy/config/environments/development.rb
... ... @@ -0,0 +1,26 @@
  1 +Dummy::Application.configure do
  2 + # Settings specified here will take precedence over those in config/application.rb
  3 +
  4 + # In the development environment your application's code is reloaded on
  5 + # every request. This slows down response time but is perfect for development
  6 + # since you don't have to restart the webserver when you make code changes.
  7 + config.cache_classes = false
  8 +
  9 + # Log error messages when you accidentally call methods on nil.
  10 + config.whiny_nils = true
  11 +
  12 + # Show full error reports and disable caching
  13 + config.consider_all_requests_local = true
  14 + config.action_view.debug_rjs = true
  15 + config.action_controller.perform_caching = false
  16 +
  17 + # Don't care if the mailer can't send
  18 + config.action_mailer.raise_delivery_errors = false
  19 +
  20 + # Print deprecation notices to the Rails logger
  21 + config.active_support.deprecation = :log
  22 +
  23 + # Only use best-standards-support built into browsers
  24 + config.action_dispatch.best_standards_support = :builtin
  25 +end
  26 +
49 test/dummy/config/environments/production.rb
... ... @@ -0,0 +1,49 @@
  1 +Dummy::Application.configure do
  2 + # Settings specified here will take precedence over those in config/application.rb
  3 +
  4 + # The production environment is meant for finished, "live" apps.
  5 + # Code is not reloaded between requests
  6 + config.cache_classes = true
  7 +
  8 + # Full error reports are disabled and caching is turned on
  9 + config.consider_all_requests_local = false
  10 + config.action_controller.perform_caching = true
  11 +
  12 + # Specifies the header that your server uses for sending files
  13 + config.action_dispatch.x_sendfile_header = "X-Sendfile"
  14 +
  15 + # For nginx:
  16 + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
  17 +
  18 + # If you have no front-end server that supports something like X-Sendfile,
  19 + # just comment this out and Rails will serve the files
  20 +
  21 + # See everything in the log (default is :info)
  22 + # config.log_level = :debug
  23 +
  24 + # Use a different logger for distributed setups
  25 + # config.logger = SyslogLogger.new
  26 +
  27 + # Use a different cache store in production
  28 + # config.cache_store = :mem_cache_store
  29 +
  30 + # Disable Rails's static asset server
  31 + # In production, Apache or nginx will already do this
  32 + config.serve_static_assets = false
  33 +
  34 + # Enable serving of images, stylesheets, and javascripts from an asset server
  35 + # config.action_controller.asset_host = "http://assets.example.com"
  36 +
  37 + # Disable delivery errors, bad email addresses will be ignored
  38 + # config.action_mailer.raise_delivery_errors = false
  39 +
  40 + # Enable threaded mode
  41 + # config.threadsafe!
  42 +
  43 + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  44 + # the I18n.default_locale when a translation can not be found)
  45 + config.i18n.fallbacks = true
  46 +
  47 + # Send deprecation notices to registered listeners
  48 + config.active_support.deprecation = :notify
  49 +end
35 test/dummy/config/environments/test.rb
... ... @@ -0,0 +1,35 @@
  1 +Dummy::Application.configure do
  2 + # Settings specified here will take precedence over those in config/application.rb
  3 +
  4 + # The test environment is used exclusively to run your application's
  5 + # test suite. You never need to work with it otherwise. Remember that
  6 + # your test database is "scratch space" for the test suite and is wiped
  7 + # and recreated between test runs. Don't rely on the data there!
  8 + config.cache_classes = true
  9 +
  10 + # Log error messages when you accidentally call methods on nil.
  11 + config.whiny_nils = true
  12 +
  13 + # Show full error reports and disable caching
  14 + config.consider_all_requests_local = true
  15 + config.action_controller.perform_caching = false
  16 +
  17 + # Raise exceptions instead of rendering exception templates
  18 + config.action_dispatch.show_exceptions = false
  19 +
  20 + # Disable request forgery protection in test environment
  21 + config.action_controller.allow_forgery_protection = false
  22 +
  23 + # Tell Action Mailer not to deliver emails to the real world.
  24 + # The :test delivery method accumulates sent emails in the
  25 + # ActionMailer::Base.deliveries array.
  26 + config.action_mailer.delivery_method = :test
  27 +
  28 + # Use SQL instead of Active Record's schema dumper when creating the test database.
  29 + # This is necessary if your schema can't be completely dumped by the schema dumper,
  30 + # like if you have constraints or database-specific column types
  31 + # config.active_record.schema_format = :sql
  32 +
  33 + # Print deprecation notices to the stderr
  34 + config.active_support.deprecation = :stderr
  35 +end
7 test/dummy/config/initializers/backtrace_silencers.rb
... ... @@ -0,0 +1,7 @@
  1 +# Be sure to restart your server when you modify this file.
  2 +
  3 +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
  4 +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
  5 +
  6 +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
  7 +# Rails.backtrace_cleaner.remove_silencers!
10 test/dummy/config/initializers/inflections.rb
... ... @@ -0,0 +1,10 @@
  1 +# Be sure to restart your server when you modify this file.
  2 +
  3 +# Add new inflection rules using the following format
  4 +# (all these examples are active by default):
  5 +# ActiveSupport::Inflector.inflections do |inflect|
  6 +# inflect.plural /^(ox)$/i, '\1en'
  7 +# inflect.singular /^(ox)en/i, '\1'
  8 +# inflect.irregular 'person', 'people'
  9 +# inflect.uncountable %w( fish sheep )
  10 +# end
5 test/dummy/config/initializers/mime_types.rb
... ... @@ -0,0 +1,5 @@
  1 +# Be sure to restart your server when you modify this file.
  2 +
  3 +# Add new mime types for use in respond_to blocks:
  4 +# Mime::Type.register "text/richtext", :rtf
  5 +# Mime::Type.register_alias "text/html", :iphone
7 test/dummy/config/initializers/secret_token.rb
... ... @@ -0,0 +1,7 @@
  1 +# Be sure to restart your server when you modify this file.
  2 +
  3 +# Your secret key for verifying the integrity of signed cookies.
  4 +# If you change this key, all old signed cookies will become invalid!
  5 +# Make sure the secret is at least 30 characters and all random,
  6 +# no regular words or you'll be exposed to dictionary attacks.
  7 +Dummy::Application.config.secret_token = 'f00fe8e4404331c84a9f1d877217c57399e0429ed948843f5d0b5db642cb2ab2c1dc28a17ef7daeecf64b1a4f2b61f7ae4886ab993fb0d7cf65d7b64ba5fbcb1'
8 test/dummy/config/initializers/session_store.rb
... ... @@ -0,0 +1,8 @@
  1 +# Be sure to restart your server when you modify this file.
  2 +
  3 +Dummy::Application.config.session_store :cookie_store, :key => '_dummy_session'
  4 +
  5 +# Use the database for sessions instead of the cookie-based default,
  6 +# which shouldn't be used to store highly confidential information
  7 +# (create the session table with "rails generate session_migration")
  8 +# Dummy::Application.config.session_store :active_record_store
5 test/dummy/config/locales/en.yml
... ... @@ -0,0 +1,5 @@
  1 +# Sample localization file for English. Add more files in this directory for other locales.
  2 +# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
  3 +
  4 +en:
  5 + hello: "Hello world"
5 test/dummy/config/routes.rb
... ... @@ -0,0 +1,5 @@
  1 +Dummy::Application.routes.draw do
  2 + resources :users, :comments
  3 +
  4 + root :to => 'users#index'
  5 +end
12 test/dummy/db/migrate/20110421191249_create_users.rb
... ... @@ -0,0 +1,12 @@
  1 +class CreateUsers < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :users do |t|
  4 + t.string :name
  5 + t.timestamps
  6 + end
  7 + end
  8 +
  9 + def self.down
  10 + drop_table :users