has_many :through :dependent => :destroy

Witam wszystkich,

Dopiero zaczynam zabawę a Rails i jak na razie bardzo mi się podoba. Uczę się z dokumentacji i artykułów w sieci, więc są pewne problemy, ale cały czas idę do przodu.
Ostatnio zacząłem bawić się relacjami, wczoraj napisałem sobie ręcznie wywalanie rekordu z modelu wskazywanego przez :through, po czym przeczytałem o istnieniu :dependent=> :destroy i postanowiłem zrobić to właśnie tak, żeby było po railsowemu:

Modele

[code]class Category < ActiveRecord::Base
has_many :categorizations
has_many :articles, :through => :categorizations, :dependent => :destroy

class Article < ActiveRecord::Base
belongs_to :user, :foreign_key => “author_id”, :class_name=>“User”
has_many :categorizations
has_many :categories, :through => :categorizations, :dependent => :destroy
validates_length_of :title, :within => 3…100
validates_length_of :body, :minimum => 10

class Categorization < ActiveRecord::Base
belongs_to :category
belongs_to :article[/code]
I teraz przy edycji artykułu, usuwa dotychczasowe kategorie i na podstawie formularza tworzy nowe:

for category in @article.categories category.destroy end if params[:cats] for category in params[:cats] cat = Categorization.new(:article_id => @article.id, :category_id => category) cat.save end end
Myślałem, że wraz z usuwanie każdej article.categories będzie zgodnie z :dependent usuwana również odpowiadająca jej kategoryzacja. Tymczasem jest błąd, wygląda na to, że sql’owski:

SystemStackError: stack level too deep: SELECT articles.* FROM articles INNER JOIN categorizations ON articles.id = categorizations.article_id WHERE ((categorizations.category_id = 1))
Pytanie co jest nie tak? Jak powinny wyglądać modele i akcja w kontrolerze, aby to działało.

Sprawa jest dosyć prosta - w obu klasach masz :dependant => :destroy co daje nieskończoną rekursję - usuwasz artykuł, co powoduje usunięcie wszystkich jego kategorii, a w nich każdego artykułu, który do nich należy, w tym artykułu, dla którego wywołałeś usuwanie. W tym artykule usuwane są wszystkie jego kategorie… i tak w kółko. Rozwiązaniem jest określenie :dependent => :destroy tylko po jednej stronie asocjacji.

Dokładnie tak, dzięki.

Korzystając z okazji chciałbym prosić o pomoc przy kolejnym problemie, pośrednio związanym z tymi relacjami. Otóż zastanawiam się w jaki kulturalny sposób zrobić stronicowane dla artykułów znajdujących się w danej kategorii. Cały czas mamy mamy takie same modele jak w pierwszym poście w temacie i teraz chce stronicować artykuły, które poprzez kategoryzację znajdują się w określonej kategorii. Dodam jeszcze, że korzystam z plugina will_paginate, ale to chyba nie będzie mieć większego znaczenia.

pozdrawiam,

Piotrek

W tym wypadku najlepiej sprawdzi się chyba paginating_find, gdyż modyfikuje metodę find, w taki sposób, że możesz jej używać na asocjacjach. Co prawda nie testowałem z :through, ale powinno działać. Więcej info pod adresem:

http://cardboardrocket.com/pages/paginating_find

A przykładowy kod z asocjacjami będzie wyglądał następująco:

c = Category.find(:first) @articles = c.articles.find(:all, :page => {:size => 10, :current => 1})
Zwróć uwagę, że dostajesz tylko jeden obiekt, a nie dwa (jak w will_paginate i oryginalnym paginatorze), co dodatkowo upraszcza sprawę (przynajmniej w moim odczuciu).