Как написать метод для всех классов - PullRequest
1 голос
/ 22 февраля 2011

Я пытаюсь написать метод, который будет применяться непосредственно к нескольким моделям с отношениями HABTM для очистки любых неиспользуемых отношений.

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

Где я могу сохранить этот метод и является ли он правильным синтаксисом для такого метода?Теоретически это будет выглядеть так:

    >>Tag.cleanup

Ответы [ 3 ]

4 голосов
/ 22 февраля 2011

Напишите внешний модуль и включите его в каждую нужную модель

2 голосов
/ 22 февраля 2011

К сожалению, люди продолжают использовать has_and_belongs_to_many, хотя это приводит к разного рода таким сиротам. Отношение has_many ..., :through может быть помечено :dependent => :destroy для автоматической очистки неиспользуемых детей. Как правило, у вас есть неиспользуемые записи о присоединении, и удалить их неприятно.

Что вы можете сделать, это подойти с точки зрения SQL, поскольку has_and_belongs_to_many записи недоступны, если их родительские записи больше не определены. Они просто не существуют в том, что касается ActiveRecord. Использование модели соединения означает, что вы всегда можете получить доступ к этим данным, поскольку им выдаются собственные идентификаторы.

has_and_belongs_to_many отношения основаны на составном ключе, что делает удаление их серьезным неудобством. Обычно вы делаете DELETE FROM table WHERE id IN (...) AND ... и уверены, что удаляются только целевые записи. С составным ключом вы не можете сделать это.

Вы можете найти эти работы для примера отношения тега к элементу:

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)

На самом деле, может быть полезно добавить первичный ключ в таблицу отношений, даже если ActiveRecord его игнорирует.

Edit:

Что касается проблемы с вашим модулем, если вы застряли с таким подходом:

module CleanupMethods
  def cleanup
    # ...
  end
end

class Tag
  # Import the module methods as class methods
  extend CleanupMethods
end

Если вы используете столбец счетного кэша, вы можете сделать это намного проще, но вам также нужно будет убедиться, что ваши счетные кэши точны.

1 голос
/ 22 февраля 2011

Вы хотите добавить метод класса к классу Tag, и вместо того, чтобы перебирать все объекты тега (требующие рельсы для загрузки каждого), а затем проверять видео через 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...