我之前做过类似的事情,但只有一层深层关联。例如。具有一个或多个地址、联系人等的帐户。
您应该确保您与其他相关模型的关联相当简单,因此没有循环或反向指针
最好以一种便于以后与模型的当前版本进行比较的方式保存它。您需要从比较中排除“原始”字段;-)
在第一次保存模型期间,我会对模型及其关联进行深度克隆,并将其保存到主模型中的序列化字段“原始”中。
我想我会使用 ActiveRecord 的serialize 功能,例如:
Class YourMainModel
...
serialize :original # will serialize this ; make this TEXT field in DB
...
end
您要确保数据库中字段的数据类型是文本或字符串,而不是二进制字段!
(这会在以后引起错误!)
然后在模型的 after_save 期间,我会添加一些代码来执行以下操作:
# do this in the after_save - so the validations have run:
main_model_object.original ||= main_model_object.deep_clone # ||= to do this only once
main_model_object.save(:validate => false) if main_model_object.original_changed? # save if we added the "copy"
可能还有其他方法可以将其挂钩,但 after_save 具有运行验证的优势。
您需要确保在第一次保存时创建了所有关联记录,可能您可能想要使用nested_forms Gem 做一个“怪物形式”。
见:
https://github.com/moiristo/deep_cloneable(Rails 3 的分叉)
https://github.com/openminds/deep_cloning(原项目)
查看其他 Ryan 的 RailsCasts:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
希望对你有帮助
编辑:
再想一想,为了限制数据库/数据库转储的大小、简化架构并安全保存原件,您可能希望将原件存储在单独的文档存储中,例如你可以使用 MongoDB。
如果您不需要经常访问原始文件,那么将其作为结构化文档存储在 MongoDB 中可能会非常有益,并且可以减少您的主应用程序的复杂性。
当你比较记录时,你会像第一次一样对修改后的模型进行 deep_clone,然后通过原始记录的 'id' 字段查找 MongoDB 记录,然后比较两者(两者都是深度克隆)。
此解决方案的附加好处:意外修改原始文件更难,因为它没有直接附加到 SQL 数据库记录。例如你不能不小心做object.original = something