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?
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 :revisionsandhas_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_revisionfield) or only revision collection.And you should probably treat
current_revisiononly 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).