Uogólnienie modelu - nadpisanie ActiveRecord::Base - dostepnosc metod

Ponieważ kilka moich modeli jest bardzo podobnych, są to róznego rodzaju komentarze, które różnią się od siebie tym, co komentują. Chciałem je sobie uogólnić i w tym celu nadpisałem ActiveRecord::Base - pod linkiem http://pastie.caboo.se/196277 jest kod. U góry “nadpis”, a niżej model który z niego korzysta.
Pojawia się problem tego typu, ze w klasie AR::Base nie znane są jeszcze metody modelu wynikające z pól tablicy bazy danych, w związku z czym mam missing method error w walidacji dla ‘author_id’. Kwestia jest tego typu, jak mam to ugryźć, aby walidacja mogła być przeprowadzana w tym “uogólnieniu”?

Walidacja to na pewno nie jest tutaj przyczyną błędu. Problemem jest tu przede wszystkim sposób w jaki probujesz to rozwiązać.
Jeśli chcesz faktycznie mieć taki model bazowy to zrób sobie klasę, z której będziesz dziedziczyć, a nie mieszaj tak w ActiveRecord::Base.

class CommentBase < ActiveRecord::Base self.abstract_class = true end
Potem możesz dziedziczyć po tej klasie.

Jak dla mnie to przypadek dla ‘polimoprhic association’: http://wiki.rubyonrails.org/rails/pages/UnderstandingPolymorphicAssociations

Zgadza się, też o tym pomyślałem, ale nie chciałem już “mącić”. Jednak to będzie lepsze rozwiązanie.

po pierwsze nie powinineś nadpisywać AR::Base, o wiele lepiej odziedziczyć ogólny model i z niego dziedziczyć poszczególne.

Dodatkowo, dlaczego nie wykorzystasz polimorfizmu, i nie użyjesz jednej tabeli z komentarzami?

ogólnie twoje rozwiązanie ale troszke bardziej eleganckie:

http://pastie.caboo.se/196344

nadal proponuje użyć polimorfizmu, i zapoznać sie lepiej z ruby, metoda validate jest już wywoływana w momencie kiedy te pola istnieją, więc to inne błędy powodują nie działanie tego kodu

Dzięki Panowie za posty, sporo mi rozjaśniły. Miałem początkowo zamiar zrobić jedną tabelę z komentarzami, ale nie bardzo wiedziałem jak przypisać je do odpowiednich, komentowanych modeli. Teraz, dzięki Waszej pomocy już wiem i zrobię to za pomocą jednej tabeli i polimorfizmu.

Po zostaje dla mnie jeszcze jedna kwestia, w której potrzebuję drobnego wyjaśnienia. Czy w kontrolerze komentarzy warto robić oddzielne akcję dla każdego typu komantarza, czy może lepiej określać typ komentowanego modelu za pomocą parametru?

pozdrawiam,

Piotr
Wykrzycz sie!

EDIT: Już sobie poradziłem. To świetna rzecz, dużo mnie pisania, tworzenia widoków i większy porządek. Jeszcze raz dzięki za powyższe posty

Odświeżam temat, bo znów mam pewien problem z uogólnianiem modelu. Tym razem sytuacja jest taka, że kilka metodeli ma pare identycznych relacji i co za tym idzie kilkanaście takich samych metod obsługujących te relacje. Aby było wszystko ładnie i pięknie, postanowiłem utworzyć klasę abstrakcyjną, po której będą te modele dziedziczyć. Jeśli chodzi o metody, to wszystko śmiga ładnie. Jednak nie mogę w tej chwili, w klasie abstrakcyjnej zadeklarować relacji, bo wyskakują błędy nie istnienia metod odnoszących się do pól z modelu z którym tworzymy relacje.Jest jakiś sposób aby wrzucić relacje do tego uogólnienia, czy trzeba będzie powtarzać je w każdym z modeli?

Poszukaj jakiegoś pluginu acts_as_* i pooglądaj źródła. Tam z reguły jest definicja tej metody acts_as_*, która do klasy, w której została wywołana, dodaje różne ciekawe rzeczy (na przykład właśnie asocjacje) itp. itd.

Wiem, że z początku może to wyglądać na zawiłe, ale jeżeli to zrozumiesz i będziesz umiał używać, to automatycznie zyskujesz bardzo fajne narzędzie do wypakowywania z aplikacji powtarzających się wzorów i wrzucania ich do pluginów (nawet jeżeli nie są to pluginy, możesz to równie dobrze wrzucić do lib/).

Jeżeli ktoś ma więcej czasu niż ja, to może będzie tak dobry i Ci wytłumaczy o co chodzi :wink: Ale najlepiej spróbuj sam, nie ma to jak obczaić jakieś coś czytając kod :wink:

Patrze po tych acts_as różnych i nie wiem na co mam patrzeć. Zazwyczaj jadą normalnie has_many czy belongs_to bez jakiś dziwów. Z tą różnicą że tam jest jazda na modułach, a ja mam klasę abstrakcyjną. Potrzebuje jakiś wskazówek żeby to rozkminić

drogus możesz rzucić jakąś podpowiedź, bo się z tym męczę już ponad tydzień?

Najprościej zacząć od starutkiego (ale wciąż działającego) pluginu acts_as_tree – jak zrozumiesz jego kod (a jeśli nie rozumiesz, musisz się podciągnąć w Rubym), zrozumiesz o co chodziło Drogusowi :slight_smile:

Okej, napisałem sobie taki plik:

[code]module ActiveRecord
module SpecialModel

  module ClassMethods
    def special_model
      has_many :comments, :as => :commentable
      has_many :ranks, :as => :rankable # dzieło ma oceny, w których zostało ocenione
      has_many :favorites, :as => :favoritable

      class_eval <<-EOV
        include ActiveRecord::SpecialModel::InstanceMethods
      EOV

    end
  end

  module InstanceMethods
     def add_view
      #metoda zwiększająca o 1 liczbę wyświetleń obiektu
      self.stat.update_attribute('views', self.stat.views + 1)
    end


  end
end

end[/code]
wrzuciłem go do lib i dałem require w environment.rb. Chciałem zobaczyć jak działa, ale jakoś źle go wrzuciłem bo mam komunikat:

gdy w modelu wywołuje metoda special_model. Gdzie i jak to powinienem wrzucić, aby było poprawnie?

Musisz odzwierciedlić hierarchię przestrzeni nazw w katalogach na dysku, tj.:

RAILS_ROOT/lib/active_record/special_model.rb

Jeśli chcesz go wrzucić bezpośrednio do RAILS_ROOT/lib, to nie umieszczaj go w przestrzeni ActiveRecord.

[quote=Piotr Misiurek]Chciałem zobaczyć jak działa, ale jakoś źle go wrzuciłem bo mam komunikat:

undefined local variable or method `special_model' for #<Class:0xb70e0634>

[/quote]
Powinieneś jeszcze dołączyć stworzony moduł do modelu:

class Something < ActiveRecord::Base extend SpecialModel::ClassMethods end

Dzięki wszystkim za pomoc, już skumałem co i jak, i wszystko wydaje się ładnie biegać. Wielki dzięki :slight_smile: