Jak dostać się do modelu linkującego w has_many :through? przy zapisie

Problem wygląda mniej więcej tak:

[code] class Page < ActiveRecord::Base
has_many_polymorphs :elements, :from => [:page_contents, :galleries, :assets]
end

model linkujacy

class ElementsPage < ActiveRecord::Base
belongs_to :page
belongs_to :element, :polymorphic => true

#jak widać zachowuje się jako lista
acts_as_list :scope => :page_id
default_scope :order => "elements_pages.position ASC"

end

modele Gallery, PageContent i Asset są właściwie mniej ważne, więc nie wklejam[/code]

Od railsów 2.3 istnieje coś takiego jak nested model mass assignment. Pomimo pewnych problemów z bezpieczeństwem, z którym trzeba się uporać, jest to bardzo przyjemny feature bardzo ułatwiający pracę przy dużej ilości asocjacji, które trzeba zapisywać przy tworzeniu i zapisie.

Problem zaczął się gdy użyłem has_many_polymorphs, a w modelu łączącym muszę zapisywać pozycję (żeby użytkownik mógł się pobawić drag&drop tymi elementami).

W scenariuszu, w którym elements istnieją i wykonuje się tylko update nie ma żadnego problemu - wystarczy przy zapisywaniu wziąć tablicę z pozycjami i ustawić je w odpowiedniej kolejności. Gorzej jest przy dodawaniu nowych rekordów - nie ma jeszcze zapisanego id, więc nie ma za bardzo jak ustawić pozycji.

Na szybko wymyśliłem coś takiego:

#moduł includowany dla każdego elementu (tzn. dla Gallery, PageContent itd...) module ActsAsElement def self.included(base) base.class_eval { attr_accessor :position } end end
Jak widać powyżej dodałem accessor position, który będzie przekazywany do elementów z formularza.

Teraz trzeba tylko nadpisać metodę, która zapisuje powiązane kolekcje.

[code] def save_collection_association(reflection)
super

# ten kod wykona się już po zapisaniu, więc mamy id i jest git ;-)
if association = association_instance_get(reflection.name)
  update_positions(association)
end

end[/code]
No i metoda update_positions, która jest wywoływana powyżej. Korzysta ona z zapisanych wcześniej w formularzu pozycji.

def update_positions(records) records.each do |record| if record.respond_to?(:elements_pages) elements_page = record.elements_pages.find(:first, :conditions => { :page_id => self.id, :element_id => record.id, :element_type => record.class.name }) end if elements_page && elements_page.position elements_page.position = record.position elements_page.save end end end
Ten kod działa i właściwie bym to tak zostawił, ale czuję jakiś wewnętrzny głos, który mi mówi, że da się to jakoś dużo prościej zrobić, tylko zabrałem się za to od zakrystii.

Widzi ktoś prostsze rozwiązanie?