如何为所有类编写方法

时间:2011-02-22 18:23:18

标签: ruby-on-rails ruby

我正在尝试编写一个直接应用于具有HABTM关系的几个模型的方法来清理任何未使用的关系。

 
   def cleanup
        self.all.each do |f|
            if f.videos.count == 0
                self.destroy(f)
            end
        end
    end

我在哪里保存此方法,这甚至是这种方法的正确语法?理论上它可以运行:

    >>Tag.cleanup

3 个答案:

答案 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