Szyny moje poglądy i kontrolery są zaśmiecone redirect_to
, link_to
i form_for
wywołań metod. Czasami link_to
i redirect_to
są jawne w ścieżkach, które łączą (np. link_to 'New Person', new_person_path
), Ale często ścieżki są niejawne (np link_to 'Show', person
.).
Dodaję dziedziczenie pojedynczej tabeli (STI) do mojego modelu (powiedzmy Employee < Person
) i wszystkie te metody przestaną działać dla instancji podklasy (powiedzmy Employee
); gdy railsy są wykonywane link_to @person
, wyświetla błędy undefined method employee_path' for #<#<Class:0x000001022bcd40>:0x0000010226d038>
. Railsy poszukują trasy zdefiniowanej przez nazwę klasy obiektu, którym jest pracownik. Te trasy pracowników nie są zdefiniowane i nie ma kontrolera pracowniczego, więc akcje też nie są zdefiniowane.
To pytanie zostało już zadane:
- W StackOverflow odpowiedzią jest edycja każdego wystąpienia link_to itp. W całej bazie kodu i jawne określenie ścieżki
- W StackOverflow ponownie dwie osoby sugerują użycie
routes.rb
do mapowania zasobów podklasy na klasę nadrzędną (map.resources :employees, :controller => 'people'
). Najlepsza odpowiedź na to samo pytanie SO sugeruje rzutowanie typów każdego obiektu instancji w bazie kodu przy użyciu.becomes
- Jeszcze inny w StackOverflow , najlepsza odpowiedź to sposób w obozie Powtarzaj się i sugeruje utworzenie zduplikowanego rusztowania dla każdej podklasy.
- Oto znowu to samo pytanie w SO, gdzie górna odpowiedź wydaje się po prostu błędna (magia Railsów po prostu działa!)
- W innym miejscu w sieci znalazłem ten wpis na blogu, w którym F2Andy zaleca edycję ścieżki w każdym miejscu kodu.
- W poście na blogu Dziedziczenie pojedynczej tabeli i RESTful Routes at Logical Reality Design zaleca się zmapowanie zasobów podklasy do kontrolera nadklasy, jak w odpowiedzi SO nr 2 powyżej.
- Alex Reisner ma posta Single Table Inheritance w Rails , w którym opowiada się przeciwko mapowanie zasobów zajęć dzieci do klasy dominującej
routes.rb
, ponieważ tylko od połowy trasy pęknięcialink_to
iredirect_to
, ale nie zform_for
. Dlatego zaleca zamiast tego dodanie metody do klasy nadrzędnej, aby podklasy kłamały na temat swojej klasy. Brzmi dobrze, ale jego metoda dała mi błądundefined local variable or method `child' for #
.
Tak więc odpowiedzią, która wydaje się najbardziej elegancka i ma największy konsensus (ale nie jest to aż tak eleganckie ani aż tak dużo konsensusu), jest dodanie zasobów do swoich routes.rb
. Tyle że to nie działa form_for
. Potrzebuję jasności! Aby wydestylować powyższe opcje, moje opcje są
- zamapuj zasoby podklasy na kontroler nadklasy w
routes.rb
(i mam nadzieję, że nie będę musiał wywoływać form_for na żadnej podklasie) - Zastąp wewnętrzne metody railsów, aby klasy okłamały się wzajemnie
- Edytuj każde wystąpienie w kodzie, w którym ścieżka do akcji obiektu jest wywoływana niejawnie lub jawnie, zmieniając ścieżkę lub rzutowanie typu obiektu.
Przy tych wszystkich sprzecznych odpowiedziach potrzebuję orzeczenia. Wydaje mi się, że nie ma dobrej odpowiedzi. Czy to błąd w projektowaniu szyn? Jeśli tak, czy jest to błąd, który można naprawić? A jeśli nie, to mam nadzieję, że ktoś może mi na to pozwolić, przeprowadzić mnie przez wady i zalety każdej opcji (lub wyjaśnić, dlaczego nie ma takiej opcji) i która z nich jest właściwą odpowiedzią i dlaczego. A może istnieje prawidłowa odpowiedź, której nie znajduję w sieci?
źródło
Odpowiedzi:
To najprostsze rozwiązanie, jakie udało mi się wymyślić, przy minimalnym efekcie ubocznym.
Teraz
url_for @person
zostanie zmapowanycontact_path
zgodnie z oczekiwaniami.Jak to działa: pomocnicy adresów URL polegają na
YourModel.model_name
refleksji nad modelem i generowaniu (między innymi) kluczy tras w liczbie pojedynczej / mnogiej. TutajPerson
jest w zasadzie mówiąc jestem jakContact
koleś, zapytaj go .źródło
build_x
/create_x
). Z drugiej strony cena zabawy magią jest taka, że nigdy nie jesteś w 100% pewien, co może się zmienić.Miałem ten sam problem. Po użyciu STI
form_for
metoda wysyłała do niewłaściwego adresu URL podrzędnego.Skończyło się na dodaniu dodatkowych tras dla klas podrzędnych i skierowaniu ich do tych samych kontrolerów
Do tego:
w tym przypadku struktura jest właściwie budynkiem (klasa potomna)
Wydaje się, że działa dla mnie po przesłaniu
form_for
.źródło
Proponuję zajrzeć na: https://stackoverflow.com/a/605172/445908 , użycie tej metody umożliwi Ci użycie „form_for”.
źródło
<%= form_for @child, :as => :child, url: @child.becomes(Parent)
<%= form_for @child.becomes(Parent)
Użyj typu w trasach:
http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-2/
źródło
Idąc za ideą @Prathan Thananart, ale starając się niczego nie zniszczyć. (ponieważ w grę wchodzi tak dużo magii)
Teraz url_for @person będzie mapowane na contact_path zgodnie z oczekiwaniami.
źródło
Ja też miałem problem z tym problemem i otrzymałem tę odpowiedź na pytanie podobne do naszego. U mnie to zadziałało.
Odpowiedź pokazana tutaj: Używanie ścieżki STI z tym samym kontrolerem
.becomes
Metoda jest zdefiniowana jako stosowane głównie do rozwiązywania problemów STI jak twójform_for
jeden..becomes
informacje tutaj: http://apidock.com/rails/ActiveRecord/Base/becomesBardzo późna odpowiedź, ale to najlepsza odpowiedź, jaką udało mi się znaleźć i działała dobrze. Mam nadzieję, że to komuś pomoże. Twoje zdrowie!
źródło
Ok, miałem mnóstwo frustracji w tym obszarze Railsów i doszedłem do następującego podejścia, być może to pomoże innym.
Przede wszystkim należy pamiętać, że wiele rozwiązań w sieci i na całym świecie sugeruje użycie stałej na parametrach podanych przez klienta. Jest to znany wektor ataku DoS, ponieważ Ruby nie zbiera śmieci, co pozwala atakującemu na tworzenie dowolnych symboli i zużywanie dostępnej pamięci.
Zaimplementowałem poniższe podejście, które obsługuje tworzenie instancji podklas modelu i jest BEZPIECZNE od powyższego problemu contantize. Jest bardzo podobny do tego, co robi rails 4, ale pozwala także na więcej niż jeden poziom podklas (w przeciwieństwie do Rails 4) i działa w Rails 3.
Po wypróbowaniu różnych podejść do problemu „ładowania podklasy w programowaniu”, wielu podobnych do tego, co zasugerowano powyżej, stwierdziłem, że jedyną rzeczą, która działała niezawodnie, było użycie parametru „require_dependency” w moich klasach modeli. Gwarantuje to, że ładowanie klas działa poprawnie podczas programowania i nie powoduje problemów w środowisku produkcyjnym. W fazie rozwoju, bez „require_dependency” AR nie będzie wiedział o wszystkich podklasach, co ma wpływ na kod SQL emitowany do dopasowania w kolumnie typu. Ponadto bez „require_dependency” możesz również znaleźć się w sytuacji z wieloma wersjami klas modelu w tym samym czasie! (np. może się to zdarzyć, gdy zmienisz klasę podstawową lub pośrednią, podklasy nie zawsze wydają się ponownie ładować i pozostają podklasy ze starej klasy)
Nie nadpisuję również nazwa_modelu, jak sugerowano powyżej, ponieważ używam I18n i potrzebuję różnych ciągów dla atrybutów różnych podklas, np .: identyfikator_podatku staje się „ABN” dla organizacji i „TFN” dla osoby (w Australii).
Korzystam też z mapowania tras, jak zasugerowałem powyżej, ustawiając typ:
Oprócz mapowania tras używam InheritedResources i SimpleForm oraz używam następującego ogólnego opakowania formularza dla nowych akcji:
... a do edycji:
Aby to zadziałało, w moim podstawowym ResourceContoller ujawniam resource_request_name InheritedResource jako metodę pomocniczą dla widoku:
Jeśli nie używasz InheritedResources, użyj czegoś podobnego do następującego w swoim „ResourceController”:
Zawsze chętnie słucham doświadczeń i ulepszeń innych.
źródło
Niedawno udokumentowałem moje próby uzyskania stabilnego wzorca STI działającego w aplikacji Rails 3.0. Oto wersja TL; DR:
Takie podejście pozwala obejść wymienione problemy, a także szereg innych problemów, które inni napotkali w związku z podejściami do chorób przenoszonych drogą płciową.
źródło
Możesz spróbować tego, jeśli nie masz zagnieżdżonych tras:
Lub możesz pójść inną drogą i użyć magii OOP, jak opisano tutaj: https://coderwall.com/p/yijmuq
Po drugie, możesz stworzyć podobne pomocniki dla wszystkich zagnieżdżonych modeli.
źródło
Oto bezpieczny, czysty sposób, aby działał w formularzach i w całej aplikacji, z której korzystamy.
Wtedy mam w swojej formie. Dodatkowym elementem jest as:: district.
Mam nadzieję że to pomoże.
źródło
Najczystszym rozwiązaniem, jakie znalazłem, jest dodanie następujących elementów do klasy bazowej:
Działa dla wszystkich podklas i jest znacznie bezpieczniejszy niż przesłanianie całego obiektu nazwy modelu. Celując tylko w klucze tras, rozwiązujemy problemy z routingiem bez przerywania I18n lub ryzyka jakichkolwiek potencjalnych skutków ubocznych spowodowanych zastąpieniem nazwy modelu zdefiniowanej przez Railsy.
źródło
Jeśli rozważę takie dziedziczenie STI:
w 'app / models / a_model.rb' dodaję:
A potem w klasie AModel:
Dlatego mogę nawet łatwo wybrać, który model chcę użyć domyślnego, i to nawet bez dotykania definicji podklasy. Bardzo suchy.
źródło
U mnie to działa w ten sposób (zdefiniuj tę metodę w klasie bazowej):
źródło
Możesz stworzyć metodę, która zwraca fikcyjny obiekt Parent w celu routingu
a następnie po prostu wywołaj form_for @ worker.routing_object, który bez typu zwróci obiekt klasy Person
źródło
Po odpowiedzi @ prathan-thananart i dla wielu klas STI możesz dodać następujące elementy do modelu nadrzędnego ->
Które uczynią każdy formularz z danymi kontaktowymi wysłać params jak
params[:contact]
zamiastparams[:contact_person]
,params[:contact_whatever]
.źródło
hackish, ale tylko kolejny do listy rozwiązań.
działa na szynach 2.x i 3.x
źródło
Child.new
, zwracaParent
klasę, a nie podklasę. Oznacza to, że nie można tworzyć podklas poprzez przypisanie masowe za pośrednictwem kontrolera (ponieważtype
jest to domyślnie chroniony atrybut), chyba że jawnie ustawisz atrybut type.