سؤال

أقوم بإنشاء ويكي. كل مقالة مراجعات ، ومقال ينتمي إلى حافة واحدة current_revision. لذلك في قاعدة البيانات ، يكون للمقالات إشارة واحدة إلى معرف المراجعة ، والمراجعات لكل منها إشارة واحدة إلى المقالة التي ينتمون إليها. قبل أن أستمر ، هل يبدو هذا بمثابة وسيلة عاقلة للقيام بالأشياء؟ إنه يذهلني على أنه غير تقليدي إلى حد ما ، لكنه منطقي ، ولست متأكدًا من كيفية إعداد الآخرين في مواقف مماثلة.

المشكلة هي أن هذا النوع من العلاقة المتبادلة يبدو أنه يطرد القضبان عند إنشاء النماذج. عندما أقوم بإنشاء مقال لأول مرة ، أود أيضًا إنشاء مراجعة أولية للذهاب إليها.

أضفت طريقة قبل _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 فارغة لأنها فاتتها الحفظ.

أعتقد أنه يمكنني الالتفاف على هذا من خلال استدعاء طريقة بعد efter_create أيضًا ، لمجرد تهيئة المتغير مع التحديث والحفظ ، لكن هذا يتحول إلى فوضى عملاقة ، وأشعر أنني في القضبان التي تعني عادةً أنني أفعل شيئًا خاطئًا -برؤوس.

هل يمكن لأي شخص أن يساعد ، أم أنني عالق في إنشاء طريقة بعد efter_create التي تحفظ في التغيير؟

هل كانت مفيدة؟

المحلول

لدي مشكلة مماثلة مؤخرًا. تحتاج إلى الإعلان عن طريقة واحدة فقط للجمعيات. هل يمكن إنشاء مقالك دون مراجعة ، ثم تمت إضافة المراجعة إلى المقالة الحالية؟

أو هل يمكنك الإشارة من مقالة إلى مراجعة لا تشير إلى الوراء؟ إذا لم يكن ذلك ممكنًا ، فأنت بحاجة إلى إعلان المراجعة 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 فقط كمؤشر للقراءة فقط. إذا حاولت تعيين مراجعة أخرى لها ، فسوف تفقد المراجعة السابقة التي تم توجيهها حسب المقالة على أنها حالية (ستقوم القضبان بإزالة الكائن القديم المرجعية ، بسبب has_one).

نصائح أخرى

المراجعة هي مجرد نسخة من مقال ، أليس كذلك؟ هناك قضبان رائعة على إصدار نموذج باستخدام 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

ومع ذلك ، في حالة حدوث تراجع ، ستحصل على زيادة عدد الإصدار من المراجعة.

أيضًا ... يمكنك التخلص من حقل الإصدار_ 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 بإدخال المراجعة بعد تم حفظ المؤلف والمقال (تمامًا مثل استخدام معالج After_create). لست متأكدًا من السبب في أن هذا يتم التعامل معه بشكل مختلف عن القيام ببناء ، لكن يبدو أنه يعمل (على الرغم من أنني لن أتفاجأ إذا لم ينجح أي شخص آخر!)

على أي حال ، آمل أن يساعد ذلك! (آسف ، لقد مضى وقت طويل بعد نشر السؤال!)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top