[Ruby] Читайте документацию или как красиво работать с many-to-many

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

Ситуация:

Есть список рассылок List, у него может быть много подписчиков Subscribers (связь многие ко многим), реализовано через третью таблицу SubscriberLists.

class List < ActiveRecord::Base

  has_many :subscriber_lists, :dependent => :destroy
  has_many :subscribers, :through => :subscriber_lists
end  

Требуется:

Выводить списки рассылки в порядке обновления, т. е. те, кто был недавно обновлен должны быть выше. Под обновлением в нашем случае понимается как изменение атрибутов List, так и добавление или удаление подписчиков в список рассылки. Решение: Для вывода списка в апи делаем:

lists = current_client.lists.by_updated_at

Кого смутило by_updated_atсюда. Великолепный гем UsefullScopes от Kaize.

Подпишем желающих(в классе List):

def add_subscriber(subscriber)  
  self.subscribers << subscriber
end  

Вот оно счастье, но тесты мне ответили красным светом. Добавление подписчика вносило изменения лишь во вспомогательную таблицу.

Тут возникла проблема: как выстроить списки в нужном порядке, если без лишних телодвижений обновления не будет.

Держа в голове, что я уже почти 3 месяца как пишу на руби, решил слазить в гугл, а не костылять сразу. Но запросы вида «как мне обновить связанную запись» выдавали исключительно информацию про accepts_nested_attributes_for, что к моей проблеме отношения не имело. Попытав удачу в течение минут 15, решил подойти к проблеме с другой стороны — можно повесить действие на изменение объекта в SubscriberLists:

def after_commit(subscriber_list)  
  subscriber_list.list.update_attributes(:updated_at => Time.zone.now)
end  

У List даем доступ на запись в updated_at

attr_accessible :updated_at

Выглядит монструозно, но работает... Но это же Ruby, но это же Rails, тут должно быть красивое решение! И оно нашлось: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html (ищем belongs_to и далее :touch)
Решением большинства проблем является фраза: RTFM, и тут прямо в точку! Пишем в SubscriberLists:

belongs_to :list, :touch => true

И все... Теперь, при добавлении подписчика происходит апдейт списка с подписчиками, и он автоматом попадет на первое место в выборке. Читайте доку внимательнее.