我创建一个wiki。每篇文章的has_many修订和belongs_to的单current_revision的文章。所以,在数据库中,文章有一处提到一个版本的ID,每个修订有一处提到他们所属的文章。我继续之前,这个问题似乎像一个理智的方式来做事?这令我相当非正统的,但逻辑和我不知道其他人在类似情况下如何设置的东西了。

麻烦的是,这种类型的相互关系belongs_to的似乎真的扔Rails的创建模型时关闭。当我第一次创建文章,我想还创建初始版本去用它。

我添加了一个before_create方法和不喜欢的东西:

initial_revision = self.revisions.build
self.current_revision = initial_revision

,但这将第一导致堆栈溢出上的保存,作为导轨显然试图在一个循环中先保存的制品,因此具有在修订的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方法?

有帮助吗?

解决方案

我最近也有类似的问题。需要声明只有一个关联的方式。可你的文章可以不修改创建,然后修改添加到现有的文章?

或者你也可以从文章修改未指回点?如果这应该是不可能的,那么你需要声明修订为belongs_to :article,以及第:has_many :revisionshas_one :revision, :conditions => { ... }。并添加标志“主要修订”修订模型或按日期得到最后版本。

这样,你不提供循环依赖,所以应该更容易。

编辑:结果 这是我测试了它,并使其工作:

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只能作为只读指针。如果您尝试指定另一个修改它,那么你会失去以前的版本,其指出文章的电流通过(Rails会删除旧引用的对象,因为has_one的)。

其他提示

一个版本仅仅是一个第一个版本,是吗?有一个伟大的Railscast上型号版本使用这应该解决您的问题vestal_versions宝石。

我觉得拥有它是让每个修订属于一个文章的最佳方式。而不是属于版本(目前),每篇文章的周期性关联。使用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

但是在回滚的情况下,你必须增加回滚到修订的版本号。

此外...您可以消除ID如果a.version_number > b.version_number且仅当a.id > b.id的version_number字段和公正的秩序。这意味着回滚将导致克隆的记录比过去的版本更高的ID。

我已经在自己的应用程序同样的问题,虽然我的结构略有不同,我终于找到了解决办法。

在我的应用我有更多的东西是这样的:

class Author < ActiveRecord::Base
  has_many :articles
  has_many :revisions
end

class Article < ActiveRecord::Base
  has_many :revisions
  belongs_to :author
end

class Revision < ActiveRecord::Base
  belongs_to :article
  belongs_to :author
end

所以我有一个3-模型环代替。

在我的情况,我要保存的整个层次(从新)一次。我发现我可以通过创建一个新的作者,然后添加文章,作者为正常做到这一点,但是当我要创建的修订,我不喜欢这样(从Author类中):

def add_new_revision(@author)
  article.revisions = article.revisions.push(Revision.new(:author => @author))
end

(注意,这里@author也没有被尚未保存)

不知何故工作原理。我注意到,在日志中,ActiveRecord的是插入修订的之后的作者和文章已经被保存(就像使用after_create处理)。我不知道这是为什么区别对待,以做构建,但它似乎工作(虽然如果没有为任何人工作,我不会感到惊讶!)

无论如何,我希望帮助! (对不起这是这么长时间,你张贴的问题后!)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top