为API包装器实现类似ActiveRecord的关联

use*_*154 11 ruby rest activerecord parsing associations

我最近编写了ParseResource,它是Parse.com的 REST api 的Ruby API包装器.

这是一些基本用法:

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

该项目相当年轻,我真正想要实现的功能是关联.像这样的东西:

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 => "alan@example.com")
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
Run Code Online (Sandbox Code Playgroud)

我喜欢任何已经实现类似功能的人以及掌握Parse REST API的人的任何建议,指示和陷阱.

Sim*_*ang 0

看起来 Parse 的工作原理是将对象存储为键值对的哈希值。所以基本上你有一个 id 和一个哈希值,你可以用它来发挥你的想象力。

要进行像 ActiveRecord 这样的关联,您需要一个主键(例如,Author.id)和一个外键(例如,Post.author_id)。Author.id 很简单 - 只需将其设为 Parse 对象的 id 即可。然后将帖子的作者 ID 存储在帖子内,以“author_id”为键。这就是数据方面。

在代码中需要考虑多个实现级别。对于检索,您的目标是创建如下方法:

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

class Post
  def author
    @author ||= Author.find(author_id)
  end
end
Run Code Online (Sandbox Code Playgroud)

这并不太难,可以通过多种方式完成,例如使用元编程。更难的是保存。至少从作者方面来看,您的目标是这样的:

class Author
  def after_save
    super
    posts.each do |p|
      p.author_id = id
      p.save
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

或者更确切地说,我应该说这就是您可能的目标,具体取决于场景。实施关联的陷阱之一是决定何时做某事。您不想让您的生活变得复杂,但您也不想为 API 调用而疯狂。考虑简单地更新作者姓名:

a = Author.find(1)
a.name = "Joe"
a.save
Run Code Online (Sandbox Code Playgroud)

正如所写的,after_save将加载现有帖子(它会通过posts设置@posts),在每个帖子上设置author_id(在本例中不需要这样做),然后保存帖子,即使没有任何更改。此外,如果帖子在保存过程中失败怎么办?在这种情况下,需要事务,以便您可以回滚整个事务并防止不一致的状态。

您可以在 ActiveRecord代码中看到,有大量逻辑围绕着保存父级时如何处理子级的问题。结果是光滑而透明的关联,但也涉及到其他各种事情;代理关联类等。

我的建议是这样的。确定您是否真的需要圆滑且透明的关联。如果没有,那么对一些访问器和便捷方法进行元编程,然后就这样。否则,花时间直接研究 ActiveRecord 关联代码或考虑DataMapper,据我所知,它为您提供了一个类似 ActiveRecord 的界面,包括关联,并且能够更改数据存储。