在 Ruby on Rails 中设置共同的 own_to
我正在创建一个维基。每篇文章都有许多修订版,并且一篇文章属于单个当前修订版。因此在数据库中,文章有一个对修订 ID 的单一引用,每个修订都有一个对其所属文章的引用。在我继续之前,这看起来是一种明智的做事方式吗?我觉得这相当非正统,但却合乎逻辑,而且我不确定其他处于类似情况的人是如何设置的。
问题在于,这种类型的相互“belongs_to”关系似乎在创建模型时确实让 Rails 感到困惑。当我第一次创建一篇文章时,我还想创建一个初始修订版来配合它。
我添加了一个 before_create 方法并执行了类似的操作:
initial_revision = self.revisions.build
self.current_revision = initial_revision
但这会导致保存时堆栈溢出,因为 Rails 显然会在循环中尝试首先保存文章,因此它有一个 Article_id 粘贴在修订版中,然后首先保存修订版,因此它有一个 current_revision_id 可以粘贴在文章中。
当我分解事物并且不同时创建它们(但仍在事务中)时,创建的第一个不会获得其引用集。 例如:
initial_revision = Revisions.create
self.current_revision = initial_revision
initial_revision.article = self
会将修订保留为空的article_id,因为它错过了保存。
我想我也可以通过调用 after_create 方法来解决这个问题,只是通过更新和保存来初始化变量,但这会变成一个巨大的混乱,我觉得在 Rails 中这通常意味着我做错了什么- 头脑发热。
任何人都可以帮忙,或者我是否坚持创建一个保存更改的小 after_create 方法?
I'm creating a wiki. Each Article has_many Revisions, and an Article belongs_to a single current_revision. So in the database, Articles have a single reference to a Revision's id, and Revisions each have a single reference to the Article they belong to. Before I continue, does this seem like a sane way to do things? It strikes me as fairly unorthodox, but logical, and I'm not sure how others in similar situations set things up.
The trouble is that this type of mutual belongs_to relationship seems to really throw Rails off when creating the models. When I first create an Article, I'd like to also create an initial Revision to go with it.
I added a before_create method and did something like:
initial_revision = self.revisions.build
self.current_revision = initial_revision
but this would cause a stack overflow on save, as Rails apparently tries in a loop to first save the Article, so it has an article_id to stick in the Revision, and then first save the Revision, so it has a current_revision_id to stick in the Article.
When I break things up, and don't create them simultaneously (but still in a transaction), the first one created doesn't get its reference set.
For example:
initial_revision = Revisions.create
self.current_revision = initial_revision
initial_revision.article = self
would leave the revision with a null article_id as it missed the save.
I think I could get around this by calling an after_create method as well, just to initialize the variable with an update and save, but this is turning into a gigantic mess, and I feel like in Rails that usually means I'm doing something wrong-headedly.
Can anyone help, or am I stuck creating a little after_create method that saves in the change?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我最近有类似的问题。您只需声明一种关联方式。您可以在不进行修订的情况下创建文章,然后将修订添加到现有文章中吗?
或者你可以从文章指向修订版而不是向后指向吗?如果这是不可能的,那么您需要将修订声明为
belongs_to :article
和 Article:has_many :revisions
和has_one :revision, :conditions => ; { ... }
。并向修订模型添加标志“主修订”或按日期获取最后修订。这样你就不会提供循环依赖,所以它应该更容易。
编辑:
这就是我测试它并使其工作的方式:
这就是它现在的工作方式(从脚本/控制台转储):
在重新加载文章上的修订集合之前,注意标记为当前的两个修订的问题。当您将其中一个修订标记为当前修订时,您需要重新加载整个文章对象(如果您想使用 current_revision 字段)或仅重新加载修订集合。
您可能应该仅将
current_revision
视为只读指针。如果您尝试为其分配另一个修订版,那么您将丢失文章所指出的当前修订版(Rails 将删除旧的引用对象,因为has_one
)。I has similar problem recently. You need to declare only one way of association. Can your Article be created without Revision, and then Revision added to existing Article?
Or can you point from Article to Revision which is not pointing back? If that should be not possible, then you need to declare Revision as
belongs_to :article
, and Article:has_many :revisions
andhas_one :revision, :conditions => { ... }
. And add flag 'main revision' to revision model or get last revision by date.This way you don't provide cyclic dependencies, so it should be easier.
Edit:
This is how I tested it and make it work:
And this is how it works now (dump from script/console):
Watch for problem with two revisions marked as current before reload revisions collection on article. When you mark one of revisions as current, then you need to reload you whole article object (if you want to use
current_revision
field) or only revision collection.And you should probably treat
current_revision
only as a read-only pointer. If you try to assign another revision to it, then you'll loose previous revision which was pointed by article as current (Rails will remove old referenced object, because ofhas_one
).修订版只是文章的一个版本,对吗? 模型版本控制上有一个很棒的 Railscast,使用
vestal_versions
gem这应该可以解决你的问题。A Revision is just a version of an Article, right? There's a great Railscast on Model Versioning using the
vestal_versions
gem which should solve your problem.我认为最好的方法是让每个修订都属于一篇文章。而不是属于修订版(当前)的每篇文章的循环关联。使用 has_one 关系将文章链接到最新版本。
但是,如果发生回滚,您将需要增加回滚到的修订版的版本号。
另外...您可以消除 version_number 字段,并在 id 上订购,如果
a.version_number > b.version_number
并且仅当a.id > 时b.id
。这意味着回滚将导致克隆记录的 ID 高于上一个版本。I think the best way to have it is to have each Revision belong to an Article. Instead of the cyclical association of each Article belonging to a Revision (Current). Use a has_one relationship to link an article to the latest revision.
However in the event of a rollback, you'll have increase the version number of the revision rolled back to.
Also... you can eliminate the version_number field and just order on id if
a.version_number > b.version_number
and only ifa.id > b.id
. Which means that rollbacks will result in cloned records with higher ids than the last version.我在自己的应用程序中遇到了同样的问题,尽管我的结构略有不同,但我终于找到了解决方案。
在我的应用程序中,我有类似这样的东西:
所以我有一个 3 模型循环。
就我而言,我想立即保存整个层次结构(从新的)。我发现我可以通过创建一个新作者,然后像平常一样将文章添加到作者来做到这一点,但是当我想创建修订时,我会这样做(在 Author 类中):(
请注意这里@author也还没有被保存)
不知何故这是有效的。我注意到在日志中,activerecord 在作者和文章保存后插入修订(就像使用 after_create 处理程序一样)。我不确定为什么这与构建不同,但它似乎有效(尽管如果它对其他人不起作用我不会感到惊讶!)
无论如何,我希望有所帮助! (抱歉,您发布问题已经过了这么久!)
I've had the same problem in my own app, and although my structure is slightly different I've finally found a solution.
In my app I have something more like this:
So I have a 3-model loop instead.
In my case, I want to save the whole hierarchy (from new) at once. I've found that I can do this by creating a new author, then adding the articles to the author as normal, but when I want to create the revisions, I do it like this (from within the Author class):
(Note that here @author hasn't been saved yet either)
Somehow this works. I've noticed that in the logs, activerecord is inserting the revision after the author and the article have been saved (just like using the after_create handler). I'm not sure why this is treated differently to doing build, but it seems to work (although I wouldn't be surprised if it didn't work for anyone else!)
Anyway, I hope that helps! (Sorry it's so long after you posted the question!)