القضبان، Attachment_fu - نسخة عميقة من مرفقات تخزين قاعدة البيانات
-
18-09-2019 - |
سؤال
لدي نموذج، دعنا نقول المرفقات، والتي تستخدم الملحق_FU لقبول تحميل الملفات من المستخدم. أريد أن "نسخة عميقة" (أو في Ruby-ese، استنساخ عميق) مرفق، وبالتالي إنشاء كائن ثنائي جديد تماما في جدول "DB_Files".
لقد وجدت أنها ليست مشكلة حل تماما حتى الآن. نشر بلوق هذا:http://www.williambharding.com/blog/Rails/Rails-faster-clonecopy-of-Actachment_fu-Images/
يظهر الطريقة التي يزعم أنها تعمل في التخزين المستندة إلى نظام الملفات. بالنسبة للمخازن المستندة إلى DB، فشل "النسخة العميقة". يتم إنشاء "مرفق" جديد ولكنه يستخدم DB_File_ID الموجود مسبقا، وبالتالي أداء نسخة ضحلة.
داخل Attachment_fu's db_file_backend.rb أرى طريقة حفظ:
# Saves the data to the DbFile model
def save_to_storage
if save_attachment?
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
true
end
لذلك، أحاول فك هذا وأعتقد أن "build_db_file" هو بعض الاختصار السحرية ل Ruby Metaprogramming ل DBFILE.NEW على الرغم من أنني لا أستطيع تأكيد هذا (GREPPING المصدر لا يذكر ذلك، ولا يمكنني العثور عليه على Google).
لست متأكدا تماما ما يفعله، لكن نظريتي هي أن DB_File يتم نسخها من المصدر OBJ كجزء من محاولة "النسخة العميقة" (في التعليمات البرمجية المرتبطة)، وبالتالي تشغيل ببساطة عن حفظ بدلا من يزيد.
كانت نظريتي الأولية هي أن كائن الوالدين (المرفق) سيتم تعيين "جديد" عند محاولة نسخ عميقة، وبالتالي فعلت شيئا مثل:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
end
end
true
end
يعمل هذا في الواقع بشكل جيد للأشياء المستنسخة ولكن لسوء الحظ فشلت جميع الاختبارات لعملية تحميل الملفات العادية غير المستنسخة. يتم إنشاء كائن المرفق ولكن لا تتم كتابة بيانات إلى DB_File. النظرية هي أن الكائن الأصل يتم حفظه أولا، ثم يتم كتابة الأشياء DB_File لاحقا، وبالتالي new_record؟ إرجاع خطأ.
لذلك، كتجربة قررت تجربة:
def save_to_storage
if save_attachment?
if self.new_record?
db_file = DbFile.new :data => temp_data
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
else
(db_file || build_db_file).data = temp_data
db_file.save!
self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
#end
end
true
end
يعمل ذلك جزئيا - يتم ملء DB_File ولكن بعد ذلك أحصل على خطأ في DB_File.Save! - قائلا أن db_file لا شيء.
لذلك، أنا نوع من المتعلمين. يمكنني أن أفعل بعض التجربة والخطأ الأخرى ولكن في هذه المرحلة، فقد أصبت بفهمي المحدود لكيفية أن يعمل هذا البرنامج المساعد. لم أكن أتوقع أو أرغب في قضاء هذا الوقت الكثير من الوقت لذلك أنا متردد في محاولة واستكشاف التعلق_FU أبعد من ذلك، لكنني أخشى أن أذهب إلى أسفل ثقب الأرنب لمعرفة ذلك. أي أفكار أو أفكار؟
شكرا!!
المحلول 2
حسنا، لذا بدلا من معرفة كيفية إنشاء DB_File جديد (وهو مهدر في حالتنا الخاصة)، أنا فقط Monkey-bratched DIMED_FILE لحذف DB_File فقط إذا لم يكن هناك المزيد من سجلات المرفقات التي تشير إليها. قد لا يكون هذا مناسبا إذا سمحت لشخص ما "بتعديل" مرفق DB_File فى الموقع ولكن لأننا لا نفعل ذلك، وهذا يعمل بشكل رائع.
Technoweenie::AttachmentFu::Backends::DbFileBackend.module_eval do
protected
def destroy_file
if db_file && self.class.count( :conditions =>["id <> ? AND db_file_id = ?", self.id, db_file.id] ) == 0
db_file.destroy
end
end
end
نصائح أخرى
هذا مجرد استجابة جزئية تشرح build_db_file
يتصل
كما اشتبهت، build_db_file
تنفذ المكالمة طريقة ولدت من خلال خلق belongs_to
منظمة. وبعد يتم إنشاء الجمعية هنا:
def self.included(base) #:nodoc:
Object.const_set(:DbFile, Class.new(ActiveRecord::Base)) unless Object.const_defined?(:DbFile)
base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id'
end
لذلك (db_file || build_db_file)
بيان يأخذ حالية مرتبطة DbFile
كائن، أو إنشاء واحدة جديدة إذا كان الأمر لا يحتوي على NIL، ويعين temp_data على حقلها الثنائي data
. وبعد ال temp_data
ربما صفيف البايت مع البيانات من النموذج.
ولدي سؤال واحد (لا أستطيع التعليق على سؤالك) - لماذا لا تتصل db_file.save!
بعد خلقها مع
db_file = DbFile.new :data => temp_data
?