我正在创建一个维基。每一篇文章has_many修订版,一篇文章belongs_to一个current_revision。因此,在数据库中,文章只有一个对修订版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方法来保存更改?
发布于 2010-02-04 00:47:35
我最近也有类似的问题。您只需要声明一种关联方式。你的文章可以在没有修订的情况下创建,然后将修订添加到现有文章中吗?
或者你可以从一篇文章指向另一篇没有回指的修订版?如果这是不可能的,那么您需要将Revision声明为belongs_to :article,并声明:has_many :revisions和has_one :revision, :conditions => { ... }。并向修订模型添加'main revision‘标志,或按日期获取最新修订。
这样,您就不会提供循环依赖,所以应该会更容易。
编辑:
这是我测试它并使其工作的方式:
class Article < ActiveRecord::Base
has_many :revisions
has_one :current_revision, :class_name => "Revision", :conditions => { :tag => "current" }
before_validation do |article|
# add current revision to list of all revisions, and mark first revision as current unless one is marked as current
article.current_revision = article.revisions.first unless article.current_revision.present?
article.revisions << article.current_revision if article.current_revision.present? and not article.revisions.member?(article.current_revision)
end
after_save do |article|
article.current_revision.mark_as_current if article.current_revision.present?
end
end
class Revision < ActiveRecord::Base
belongs_to :article
def mark_as_current
Revision.update_all("tag = ''", :article_id => self.article_id)
self.tag = "current"
save!
end
end这就是它现在的工作方式(从脚本/控制台转储):
$ ./script/console
Loading development environment (Rails 2.3.5)
>> a1 = Article.new :name => "A1"
>> a1.revisions.build :number => 1
>> a1.save
>> a1.reload
>> a1.revisions
+----+------------+--------+---------+-------------------------+-------------------------+
| id | article_id | number | tag | created_at | updated_at |
+----+------------+--------+---------+-------------------------+-------------------------+
| 1 | 1 | 1 | current | 2010-02-03 19:10:37 UTC | 2010-02-03 19:10:37 UTC |
+----+------------+--------+---------+-------------------------+-------------------------+
>> a1.current_revision
+----+------------+--------+---------+-------------------------+-------------------------+
| id | article_id | number | tag | created_at | updated_at |
+----+------------+--------+---------+-------------------------+-------------------------+
| 1 | 1 | 1 | current | 2010-02-03 19:10:37 UTC | 2010-02-03 19:10:37 UTC |
+----+------------+--------+---------+-------------------------+-------------------------+
>> a1r2 = a1.revisions.build :number => 2
+------------+--------+-----+------------+------------+
| article_id | number | tag | created_at | updated_at |
+------------+--------+-----+------------+------------+
| 1 | 2 | | | |
+------------+--------+-----+------------+------------+
>> a1r2.mark_as_current
>> a1.revisions
+----+------------+--------+---------+-------------------------+-------------------------+
| id | article_id | number | tag | created_at | updated_at |
+----+------------+--------+---------+-------------------------+-------------------------+
| 1 | 1 | 1 | current | 2010-02-03 19:10:37 UTC | 2010-02-03 19:10:37 UTC |
| 2 | 1 | 2 | current | 2010-02-03 19:11:44 UTC | 2010-02-03 19:11:44 UTC |
+----+------------+--------+---------+-------------------------+-------------------------+
>> a1.revisions.reload
+----+------------+--------+---------+-------------------------+-------------------------+
| id | article_id | number | tag | created_at | updated_at |
+----+------------+--------+---------+-------------------------+-------------------------+
| 1 | 1 | 1 | | 2010-02-03 19:10:37 UTC | 2010-02-03 19:10:37 UTC |
| 2 | 1 | 2 | current | 2010-02-03 19:11:44 UTC | 2010-02-03 19:11:44 UTC |
+----+------------+--------+---------+-------------------------+-------------------------+
>> a1.current_revision
+----+------------+--------+---------+-------------------------+-------------------------+
| id | article_id | number | tag | created_at | updated_at |
+----+------------+--------+---------+-------------------------+-------------------------+
| 1 | 1 | 1 | current | 2010-02-03 19:10:37 UTC | 2010-02-03 19:10:37 UTC |
+----+------------+--------+---------+-------------------------+-------------------------+
>> a1.reload
>> a1.current_revision
+----+------------+--------+---------+-------------------------+-------------------------+
| id | article_id | number | tag | created_at | updated_at |
+----+------------+--------+---------+-------------------------+-------------------------+
| 2 | 1 | 2 | current | 2010-02-03 19:11:44 UTC | 2010-02-03 19:11:44 UTC |
+----+------------+--------+---------+-------------------------+-------------------------+在文章上重新加载修订版集合之前,请查看标记为当前版本的两个修订版的问题。当您将其中一个修订标记为当前修订时,您需要重新加载整个文章对象(如果您希望使用current_revision字段)或仅重新加载修订集合。
而且您可能应该只将current_revision视为只读指针。如果你试图给它分配另一个修订版,那么你就会丢失之前的修订版,该修订版被文章作为当前版本(由于has_one,Rails将删除旧的被引用的对象)。
发布于 2010-02-04 00:47:44
修改只是一篇文章的一个版本,对吧?在使用vestal_versions gem的Model Versioning上有一个很棒的铁路广播,它应该可以解决你的问题。
发布于 2010-02-04 01:36:46
我认为最好的方法是让每个版本都属于一篇文章。而不是属于某个修订版的每个条款的周期性关联(当前)。使用has_one关系将文章链接到最新修订。
class Revision < ActiveRecord::Base
belongs_to :article
...
end
class Article < ActiveRecord::Base
has_many :revisions
has_one :current_revision, :order => "version_number DESC"
...
end但是,在回滚的情况下,您需要增加回滚到的修订的版本号。
还有..。您可以删除version_number字段,仅当a.version_number > b.version_number且仅当a.id > b.id时按id排序。这意味着回滚将导致克隆的记录具有比上一个版本更高的ids。
https://stackoverflow.com/questions/2193582
复制相似问题