我正在尝试编写一个直接应用于具有HABTM关系的几个模型的方法来清理任何未使用的关系。
def cleanup self.all.each do |f| if f.videos.count == 0 self.destroy(f) end end end
我在哪里保存此方法,这甚至是这种方法的正确语法?理论上它可以运行:
>>Tag.cleanup
答案 0 :(得分:4)
编写外部模块并将其包含在您需要的每个模型中
答案 1 :(得分:2)
可悲的是,人们继续使用has_and_belongs_to_many
,即使它会导致像这样的各种孤儿。可以标记has_many ..., :through
关系:dependent => :destroy
以自动清理未使用的子项。通常情况下,您将使用未使用的连接记录并且它们是令人讨厌的删除。
您可能会做的是从SQL角度处理此问题,因为如果不再定义其父记录,则has_and_belongs_to_many
记录将无法访问。就ActiveRecord而言,它们根本就不存在。使用连接模型意味着您始终可以访问此数据,因为它们是自己的ID。
has_and_belongs_to_many
关系基于复合键,这使得删除它们非常麻烦。通常你会做DELETE FROM table WHERE id IN (...) AND ...
并确信只删除了目标记录。使用复合键,您无法执行此操作。
您可能会发现这适用于Tag to Item关系的示例:
DELETE FROM item_tags, tags, items WHERE item_tags.tag_id=tags.id AND item_tags.item_id=items.id AND tags.id IS NULL AND items.id IS NULL
DELETE
语句可能非常特别关于它如何操作,并且不会给SELECT
提供与DELETE FROM item_tags WHERE id IN (SELECT id FROM item_tags LEFT JOIN tags ON item_tags.tag_id=tags.id LEFT JOIN items ON item_tags.item_id=items.id WHERE tags.id IS NULL AND items.id IS NULL)
相同的自由度,其连接可以根据需要定义为左或右,内部或外部。< / p>
如果您在联接表中有主ID,则可以轻松完成:
module CleanupMethods
def cleanup
# ...
end
end
class Tag
# Import the module methods as class methods
extend CleanupMethods
end
事实上,即使ActiveRecord忽略了主键,也可能有利于在关系表中添加主键。
编辑:
至于你的模块问题,如果你坚持这种方法:
{{1}}
如果您使用计数器缓存列,则可以更轻松地执行此操作,但您还必须确保计数器缓存准确无误。
答案 2 :(得分:1)
您希望向Tag类添加一个类方法,而不是遍历所有标记对象(需要使用rails来加载每个标记对象),然后通过Active Record检查视频,使用加载所有孤立记录的速度更快查询,然后只销毁那些。
猜测你有标签和视频,并且tag_videos是你的连接表,在Rails 2.x中你可以写
def self.cleanup
find(:all, :conditions => "id NOT IN (select tag_id from tag_videos)").destroy_all
end
在Rails 3中你会写
def self.cleanup
where("id NOT IN (select tag_id from tag_videos)").destroy_all
end