让我们保持简单.假设我有一个用户模型和一个邮政模型:
class User < ActiveRecord::Base # id:integer name:string deleted:boolean has_many :posts end class Post < ActiveRecord::Base # id:integer user_id:integer content:string deleted:boolean belongs_to :user end
现在,我们来说一个管理员想“删除”(隐藏)一个帖子.所以基本上他通过系统把一个帖子的已删除的属性设置为1.我该如何在视图中显示这个帖子?我应该在这个帖子上创建一个虚拟属性:
class Post < ActiveRecord::Base # id:integer user_id:integer content:string deleted:boolean belongs_to :user def administrated_content if !self.deleted self.content else "This post has been removed" end end end
虽然这样会起作用,但我想在大量的模型中实现上述,我不禁感觉到将上述比较文字粘贴到我所有的模型中都可以是DRYER.很多烘干机.
我也认为,在我的应用程序中,每一个可删除的模型中都删除了一个列,也有点麻烦.我觉得我应该有一个’状态’表.你对此有何想法?
class State #id:integer #deleted:boolean #deleted_by:integer belongs_to :user belongs_to :post end
然后在比较器中查询self.state.deleted?这需要一个多态表吗?我只尝试过多态,我无法让它工作. (这是一个非常复杂的自我参照模式,心灵).这仍然没有解决在我的模型中有一个非常非常相似的类方法以检查在显示内容之前是否删除实例的问题.
在deleted_by属性中,我正在考虑将管理员的ID删除.但是管理员取消删除帖子怎么办?也许我应该有一个edited_by id.
如何设置依赖关系::用户和他的帖子之间的销毁类型关系?因为现在我想这样做:依赖::set_deleted_to_0,我不知道该怎么做.
此外,我们不仅仅希望将帖子的已删除属性设置为1,因为我们实际上想要更改我们的administrationated_content发出的消息.我们现在想要说的是,由于其用户已被删除,此帖子已被删除.我相信我可以跳进去做一些奇怪的事情,但我想从一开始就做好准备.
我也尽量避免宝石,因为我觉得我错过了学习.
解决方法
在这种情况下,我通常使用一个名为deleted_at的字段:
class Post < ActiveRecord::Base scope :not_deleted,lambda { where(deleted_at: nil) } scope :deleted,lambda { where("#{self.table_name}.deleted_at IS NOT NULL") } def destroy self.update_attributes(deleted_at: DateTime.current) end def delete destroy end def deleted? self.deleted_at.present? end # ...
=>扩展它吧!
# lib/extensions/act_as_fake_deletable.rb module ActAsFakeDeletable # override the model actions def delete self.update_attributes(deleted_at: DateTime.current) end def destroy self.update_attributes(deleted_at: DateTime.current) end # define new scopes def self.included(base) base.class_eval do scope :deleted,where('deleted_at IS NOT NULL') scope :not_deleted,where('deleted_at IS NULL') scope :destroyed,where('deleted_at IS NOT NULL') scope :not_destroyed,where('deleted_at IS NULL') end end end class ActiveRecord::Base def self.act_as_fake_deletable(options = {}) alias_method :destroy!,:destroy alias_method :delete!,:delete include ActAsFakeDeletable options = { field_to_hide: :content,message_to_show_instead: "This content has been deleted" }.merge!(options) define_method options[:field_to_hide].to_sym do return options[:message_to_show_instead] if self.deleted_at.present? self.read_attribute options[:field_to_hide].to_sym end end end
用法:
class Post < ActiveRecord::Base act_as_fake_deletable
覆盖默认值:
class Book < ActiveRecord::Base act_as_fake_deletable field_to_hide: :title,message_to_show_instead: "This book has been deleted man,sorry!"
繁荣!完成.