2011-10-09 11 views
11

Recientemente escribí ParseResource, que es un contenedor Ruby API para Parse.com's REST api.Implementación de asociaciones similares a ActiveRecord para un contenedor API

Aquí hay un poco de uso básico:

class Post < ParseResource 
    fields :title, :author, :body 
end 
p = Post.create(:title => "Hello world", :author => "Alan", :body => "ipso lorem") 

El proyecto es bastante joven, y una característica que realmente quiero es poner en práctica las asociaciones. Algo como esto:

class Author < ParseResource 
    has_many :posts 
    fields :name, :email 
end 
class Post < ParseResource 
    belongs_to :author 
    fields :title, :body 
end 
a = Author.create(:name => "Alan", :email => "[email protected]") 
p = Post.create(:title => "Associated!", :body => "ipso lorem", :author => a) 
p.author.class #=> Author 
p.author.name #=> "Alan" 
a.posts #=> an array of Post objects 

me encantaría algún consejo, punteros, y las trampas de cualquier persona que ha puesto en marcha algo similar, así como de cualquier persona que tenga una idea de la API REST de analizar.

+0

¿Has oído hablar de [nulldb] (https://github.com/nulldb/nulldb)? –

Respuesta

0

Parece que Parse funciona almacenando objetos como un hash de pares clave-valor. Así que básicamente tienes una identificación y luego un hash con el que puedes dejar volar tu imaginación.

Para realizar asociaciones como ActiveRecord necesita una clave principal (por ejemplo, Author.id) y una clave externa (por ejemplo, Post.author_id). Author.id es simple, solo conviértalo en el id del objeto Parse. Luego, guarde la identificación del autor para una publicación dentro de la publicación, con la tecla 'author_id'. Entonces ese es el lado de los datos.

En el código hay varios niveles de implementación a considerar. Para la recuperación que está destinado a hacer que los métodos de esta manera:

class Author 
    def posts 
    @posts ||= Post.find(:all, :id => id) 
    end 
end 

class Post 
    def author 
    @author ||= Author.find(author_id) 
    end 
end 

Eso no es demasiado difícil y se puede hacer de muchas maneras, por ejemplo usando metaprogramming. Más difícil es salvar. Lo que usted está apuntando para, al menos desde el lado del autor, es algo como esto:

class Author 
    def after_save 
    super 
    posts.each do |p| 
     p.author_id = id 
     p.save 
    end 
    end 
end 

O más bien debería decir que es lo que podría ser el objetivo para la función del escenario. Uno de los peligros de implementar asociaciones es decidir cuándo hacer las cosas. No quiere complicar su vida, pero tampoco quiere volverse loco con las llamadas API. Considere simplemente actualizando el nombre de un autor:

a = Author.find(1) 
a.name = "Joe" 
a.save 

Como está escrito after_save cargará puestos existentes (que pasa a través posts que establece @posts), establecidos author_id en cada poste (que no necesita ser hecho en este caso), y luego guarde las publicaciones aunque nada las haya cambiado. Además, ¿qué sucede si una publicación falla durante el guardado? En ese caso, las transacciones son necesarias para que pueda deshacer todo y evitar un estado incoherente.

Puede ver en el ActiveRecord code hay una tonelada de lógica que rodea la cuestión de cómo manejar los elementos secundarios cuando se guarda un elemento primario. El resultado son las asociaciones resbaladizas y transparentes, pero todo tipo de otras cosas se involucran; proxies, association classes, etc.

Mi consejo es esto. Decida si realmente necesita asociaciones resbaladizas y transparentes. Si no, metaprograme algunos accesos y métodos de conveniencia y déjelo así. De lo contrario, dedique un tiempo a estudiar directamente el código de la asociación ActiveRecord o considere DataMapper que, AFAIK, le ofrece una interfaz similar a ActiveRecord, que incluye asociaciones, con la capacidad de cambiar los almacenes de datos.

Cuestiones relacionadas