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

发布于 2024-12-08 17:07:34 字数 1074 浏览 0 评论 0 原文

我最近写了 ParseResource,它是 Parse.com 的 REST API。

这是一些基本用法:

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

该项目相当年轻,我真正想要实现的一个功能是关联。像这样的事情:

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

我希望任何已经实现了类似功能的人以及任何掌握 Parse 的 REST API 的人提供任何建议、指示和陷阱。

I recently wrote ParseResource, which is a Ruby API wrapper for Parse.com's REST api.

Here's a some basic usage:

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

The project is fairly young, and a feature I really want to implement is associations. Something like this:

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

I'd love any advice, pointers, and pitfalls from anyone who has implemented something similar as well as from anyone who has a grasp of Parse's REST API.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温柔戏命师 2024-12-15 17:07:34

我发现使用 DataMapper ( http://datamapper.org ) 可以很容易地使其与几乎任何数据存储区一起使用。您可以编写一个与数据存储区通信的适配器,然后直接使用 DataMapper 的所有功能,就像您的数据位于 SQL 中一样。这是一个链接,解释了有关编写这些适配器之一的一些信息。 http://www.killswitchcollective.com/articles/55_datamapperabstractadapter_101

I've found using DataMapper ( http://datamapper.org ) it's pretty easy to get it working with almost any datastore. You can write an adapter that talks to your datastore and then use all of the power of DataMapper directly as if your data was in SQL. Here's a link that explains a bit about writing one of these adapters. http://www.killswitchcollective.com/articles/55_datamapperabstractadapter_101

哽咽笑 2024-12-15 17:07:34

看起来 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

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

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

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

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

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

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

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

It looks like Parse works by storing objects as a hash of key-value pairs. So basically you have an id and then a hash with which you can let your imagination run.

To do associations like ActiveRecord you need a primary key (e.g., Author.id) and a foreign key (e.g., Post.author_id). The Author.id is simple - just make it the id of the Parse object. Then store the author id for a post inside the post, keyed by 'author_id'. So that's the data side.

In the code there are several levels of implementation to consider. For retrieval you're aiming to make methods like this:

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

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

That's not too hard and can be done in many ways, for instance using metaprogramming. Harder is the save. What you're aiming for, at least from the Author side, is something like this:

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

Or rather I should say that's what you might be aiming for depending on the scenario. One of the pitfalls in implementing associations is deciding when to do stuff. You don't want to complicate your life, but you also don't want to go crazy with API calls. Consider simply updating the name of an author:

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

As written after_save will load existing posts (it goes through posts which sets @posts), set author_id on each post (which need not be done in this case), and then save the posts even though nothing has changed them. Moreover what if a post fails during save? In that case transactions are needed so you can rollback the whole thing and prevent an inconsistent state.

You can see in the ActiveRecord code there is a ton of logic surrounding the issue of how to handle children when a parent is saved. The result is the slick and transparent associations but all kinds of other things get involved; proxies, association classes, etc.

My advice is this. Decide if you really need slick and transparent associations. If not then metaprogram a few accessors and convenience methods and leave it at that. Otherwise, spend time studying the ActiveRecord association code directly or consider DataMapper which, AFAIK, gives you an ActiveRecord-like interface, including associations, with the ability to change data stores.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文