Вопрос

Я создаю вики.Каждая статья имеет_множество редакций, и статья принадлежит_одной текущей_редакции.Таким образом, в базе данных статьи имеют одну ссылку на идентификатор редакции, а каждая редакция имеет одну ссылку на статью, к которой они принадлежат.Прежде чем я продолжу, кажется ли это разумным способом сделать что-то?Мне это кажется довольно неортодоксальным, но логичным, и я не уверен, как другие в подобных ситуациях поступают.

Проблема в том, что этот тип взаимного отношения «принадлежит_к», кажется, действительно сбивает Rails с толку при создании моделей.Когда я впервые создаю статью, я хотел бы также создать для нее начальную редакцию.

Я добавил метод before_create и сделал что-то вроде:

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

но это может вызвать переполнение стека при сохранении, так как Rails, очевидно, пытается в цикле сначала сохранить статью, поэтому у него есть item_id для прикрепления к ревизии, а затем сначала сохраняется ревизия, поэтому у него есть current_revision_id для прикрепления к ревизии. Статья.

Когда я разбиваю вещи и не создаю их одновременно (но все еще в транзакции), первый созданный объект не получает набора ссылок.Например:

initial_revision = Revisions.create
self.current_revision = initial_revision
initial_revision.article = self

оставил бы ревизию с нулевым идентификатором статьи, поскольку не сохранился.

Я думаю, что мог бы обойти это, вызвав метод after_create, просто для того, чтобы инициализировать переменную с обновлением и сохранением, но это превращается в гигантский беспорядок, и я чувствую, что в Rails это обычно означает, что я делаю что-то не так. - головой.

Может ли кто-нибудь помочь, или я застрял в создании небольшого метода after_create, который сохраняет изменения?

Это было полезно?

Решение

Недавно у меня возникла похожая проблема.Вам нужно объявить только один способ ассоциации.Может ли ваша статья быть создана без редакции, а затем добавлена ​​редакция к существующей статье?

Или вы можете указать от статьи к редакции, которая не указывает назад?Если это невозможно, вам необходимо объявить Revision как belongs_to :article, и статья :has_many :revisions и has_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).

Другие советы

Редакция - это просто версия статьи, верно? Есть отличное железнодорожное постановление на Модель версификация с использованием vestal_versions GEM, которая должна решить вашу проблему.

Я думаю, что лучший способ иметь это, чтобы каждый пересмотр принадлежать статье. Вместо циклической ассоциации каждой статьи, принадлежащей к ревизии (току). Используйте отношения 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

Однако в случае отката вы будете увеличить номер версии ревизии обратно.

Также ... вы можете устранить поле версии_Number и просто заказать на ID, если a.version_number > b.version_number И только если a.id > b.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-модельная петля.

В моем случае я хочу сэкономить всю иерархию (от нового) сразу. Я обнаружил, что могу сделать это, создав новый автор, затем добавляя статьи автору как обычно, но когда я хочу создать изменения, я делаю это, как это (из-за класса автора):

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

(Обратите внимание, что здесь @author еще не сохранен)

Как-то это работает. Я заметил, что в журналах ActiveRecord вставляет ревизию после Автор и статья были сохранены (как правило, используя обработчик Affo_Create). Я не уверен, почему это относится к по-разному, чтобы делать постройки, но, похоже, работает (хотя я не буду удивлен, если бы не сработал для кого-либо еще!)

Во всяком случае, я надеюсь, что поможет! (Извините, это так долго после того, как вы разместили вопрос!)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top