Estou trabalhando em um aplicativo chamado Apphakker . Neste aplicativo, os usuários podem completar atribuições. Ao concluir uma tarefa, eles reivindicam uma conquista e recebem pontos.
Essas atribuições são coisas como “criar um controlador em seu aplicativo Rails” ou “implantar uma atualização no Heroku”. Cada atribuição tem seu próprio código de validação na forma de uma classe Ruby. Por exemplo, tenho um ControllerCreatedAssignment.
Preciso ser capaz de salvar se um usuário concluiu uma atribuição no banco de dados. Então, eu criei um modelo de atribuição em meus aplicativos Rails que tem um relacionamento e pertence a muitos com o Player (a conta do usuário). Para cada tarefa disponível para jogadores, eu tenho um objeto Atribuição em meu banco de dados. Cada atribuição possui uma coluna que contém a classe Ruby associada.
Então, como faço para executar a classe Ruby apropriada de uma coluna de string no banco de dados? Aqui está o código do controlador responsável por verificar se um jogador concluiu uma atribuição:
class AchievementsController < ApplicationController
before_filter :authenticate_player!
def claim
@assignment = Assignment.find(params[:id])
if @assignment.unlocked?
current_player.assignments << @assignment
render
else
render :nothing => true
end
end
end
O controlador acima busca o objeto Assignment do banco de dados com base no id que é inserido. Em seguida, ele chama desbloqueado? na atribuição para verificar se um jogador completou a atribuição.
O código no modelo de Atribuição se parece com este:
class Assignment < ActiveRecord::Base
attr_accessible :name, :ruby_class
delegate :unlocked?, :to => :validator
def validator
@validator ||= ruby_class.constantize.new()
end
end
Em primeiro lugar, existe um método delegado, que delega uma chamada para o desbloqueado? método para um objeto que é retornado pelo método validador .
O método validator , por sua vez, pega o nome da classe como uma string do banco de dados, constante-a em uma classe Ruby e chama o “novo” método nela para inicializar um objeto.
Portanto, digamos que eu tenha uma atribuição em meu banco de dados que precise executar o código da classe ControllerCreatedAssignment.
Primeiro, pego o objeto de modelo de atribuição apropriado do banco de dados por sua chave primária.
Em seguida, pego a string da coluna ruby_class *, que neste caso contém a string ** “ControllerCreatedAssignment” . Constantizando-o, obtenho uma classe Ruby real ControllerCreatedAssignment que tem um ? método de instância. Eu chamo de atribuição. Desbloqueado? que por sua vez chama desbloqueado? em um objeto da classe ControllerCreatedAssignment, que retorna verdadeiro ou falso se a atribuição foi concluída.
Esta é a aparência de ControllerCreatedAssignment:
class ControllerCreatedAssignment
def unlocked?
# Clone git
# Check for a _controller in app/controllers
# return true or false
end
end