Mam kilka modeli, które mają wywołania zwrotne after_save. Zwykle jest to w porządku, ale w niektórych sytuacjach, na przykład podczas tworzenia danych programistycznych, chcę zapisać modele bez uruchamiania wywołań zwrotnych. Czy jest na to prosty sposób? Coś w rodzaju ...
Person#save( :run_callbacks => false )
lub
Person#save_without_callbacks
Zajrzałem do dokumentacji Rails i nic nie znalazłem. Jednak z mojego doświadczenia wynika, że dokumentacja Rails nie zawsze opisuje całą historię.
AKTUALIZACJA
Znalazłem post na blogu, w którym wyjaśniono, jak usunąć wywołania zwrotne z takiego modelu:
Foo.after_save.clear
Nie mogłem znaleźć, gdzie ta metoda jest udokumentowana, ale wydaje się, że działa.
Foo.after_save.clear
usunąłbyś wywołań zwrotnych dla całego modelu? A więc jak proponujesz je przywrócić?Odpowiedzi:
To rozwiązanie dotyczy tylko Rails 2.
Właśnie to zbadałem i myślę, że mam rozwiązanie. Istnieją dwie prywatne metody ActiveRecord, których możesz użyć:
Będziesz musiał użyć funkcji send, aby wywołać te metody. przykłady:
Jest to zdecydowanie coś, czego naprawdę będziesz chciał używać tylko w konsoli lub podczas wykonywania losowych testów. Mam nadzieję że to pomoże!
źródło
Użyj
update_column
(Rails> = v3.1) lubupdate_columns
(Rails> = 4.0), aby pominąć wywołania zwrotne i walidację. Również w przypadku tych metod nieupdated_at
jest aktualizowany.http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column
# 2: Pomijanie wywołań zwrotnych, które działają również podczas tworzenia obiektu
źródło
:create_without_callbacks
:( Jak mogę uruchomić coś podobnego do tego? (Działał w Rails2, usunięty w Rails3).@person
jest to zmienna gdzieś w kontrolerze, to rozwiązanie oznacza, że osoby czytające klasę modelu nie będą w stanie zrozumieć wywołań zwrotnych. Zobacząafter_create :something_cool
i pomyślą „świetnie, po stworzeniu dzieje się coś fajnego!”. Aby właściwie zrozumieć twoją klasę modelu, będą musieli przeszukać wszystkie kontrolery, szukając wszystkich małych miejsc, w których zdecydowałeś się wprowadzić logikę. Nie podoba mi się to> o <;;skip_callback ..., if: :skip_some_callbacks
zeafter_create ..., unless: :skip_some_callbacks
uruchomić to właściwie z after_create.Zaktualizowano:
Rozwiązanie @Vikrant Chaudhary wydaje się lepsze:
Moja pierwotna odpowiedź:
zobacz ten link: Jak pominąć wywołania zwrotne ActiveRecord?
w Rails3,
załóżmy, że mamy definicję klasy:
Podejście 1:
Podejście 2: Jeśli chcesz pominąć je w swoich plikach rspec lub czymkolwiek, spróbuj tego:
UWAGA: po wykonaniu tej czynności, jeśli nie jesteś w środowisku rspec, powinieneś zresetować wywołania zwrotne:
u mnie działa dobrze na szynach 3.0.5
źródło
szyny 3:
źródło
reset_callbacks
nie jest:after_save
, ale raczej:save
. apidock.com/rails/v3.0.9/ActiveSupport/Callbacks/ClassMethods/ ...Jeśli celem jest po prostu wstawienie rekordu bez wywołań zwrotnych lub walidacji, a chciałbyś to zrobić bez uciekania się do dodatkowych klejnotów, dodawania sprawdzeń warunkowych, używania RAW SQL lub w jakikolwiek inny sposób z zamykającym kodem, rozważ użycie „shadow obiekt ”wskazujący na istniejącą tabelę db. Tak jak to:
Działa to z każdą wersją Railsów, jest bezpieczne dla wątków i całkowicie eliminuje wszelkie walidacje i wywołania zwrotne bez modyfikacji istniejącego kodu. Możesz po prostu wrzucić tę deklarację klasy tuż przed rzeczywistym importem i powinieneś być gotowy. Pamiętaj tylko, aby użyć nowej klasy do wstawienia obiektu, na przykład:
źródło
Możesz spróbować czegoś takiego w swoim modelu Person:
EDYCJA: after_save nie jest symbolem, ale przynajmniej po raz tysięczny próbowałem to zrobić.
źródło
send
. KOODOSMożesz użyć
update_columns
:źródło
Jedynym sposobem uniknięcia wszystkich wywołań zwrotnych after_save jest ustawienie pierwszego zwracającego false.
Być może mógłbyś spróbować czegoś takiego (niesprawdzone):
źródło
Wygląda na to, że jednym ze sposobów radzenia sobie z tym problemem w Railsach 2.3 (ponieważ aktualizacja_without_callbacks już nie istnieje, itd.), Byłoby użycie update_all, jednej z metod pomijających wywołania zwrotne zgodnie z sekcją 12 Przewodnika po walidacji i wywołania zwrotne Rails .
Zwróć również uwagę, że jeśli robisz coś w swoim wywołaniu zwrotnym after_, który wykonuje obliczenia oparte na wielu skojarzeniach (np. Asoc_as_many, gdzie również akceptujesz_nested_attributes_for), będziesz musiał ponownie załadować skojarzenie, na wypadek gdyby było częścią zapisywania , jeden z jego członków został usunięty.
źródło
https://gist.github.com/576546
po prostu zrzuć tę małpą łatkę do config / initializers / skip_callbacks.rb
następnie
Project.skip_callbacks { @project.save }
lub tym podobne.
wszystkie zasługi dla autora
źródło
W
up-voted
niektórych przypadkach większość odpowiedzi może wydawać się zagmatwana.Możesz użyć prostego
if
sprawdzenia, czy chcesz pominąć oddzwonienie, na przykład:źródło
Rozwiązaniem, które powinno działać we wszystkich wersjach Railsów bez użycia klejnotu lub wtyczki, jest po prostu bezpośrednie wydawanie instrukcji update. na przykład
Może to być opcja (lub nie) w zależności od stopnia złożoności aktualizacji. Działa to dobrze na przykład flagi aktualizowanie na rekord od wewnątrz na after_save zwrotnego (bez ponownego wyzwolenia wywołania zwrotnego).
źródło
#{...}
.źródło
Żaden z tych punktów nie wskazuje na
without_callbacks
wtyczkę, która po prostu robi to, czego potrzebujesz ...http://github.com/cjbottaro/without_callbacks działa z Railsami 2.x
źródło
Napisałem wtyczkę, która implementuje update_without_callbacks w Railsach 3:
http://github.com/dball/skip_activerecord_callbacks
Myślę, że właściwym rozwiązaniem jest przepisanie modeli, aby przede wszystkim uniknąć wywołań zwrotnych, ale jeśli jest to niepraktyczne w najbliższym czasie, ta wtyczka może pomóc.
źródło
Jeśli używasz Railsów 2. Możesz użyć zapytania SQL do aktualizacji swojej kolumny bez wywołań zwrotnych i walidacji.
Myślę, że powinno działać w każdej wersji szynowej.
źródło
Gdy potrzebuję pełnej kontroli nad wywołaniem zwrotnym, tworzę inny atrybut, który jest używany jako przełącznik. Prosty i skuteczny:
Model:
Test:
źródło
Do tworzenia danych testowych w Railsach używasz tego hacka:
https://coderwall.com/p/y3yp2q/edit
źródło
Możesz użyć klejnotu podstępnego zapisu: https://rubygems.org/gems/sneaky-save .
Pamiętaj, że nie może to pomóc w zapisywaniu skojarzeń bez walidacji. Zgłasza błąd „created_at nie może być null”, ponieważ bezpośrednio wstawia zapytanie sql w przeciwieństwie do modelu. Aby to zaimplementować, musimy zaktualizować wszystkie automatycznie generowane kolumny bazy danych.
źródło
Potrzebowałem rozwiązania dla Rails 4, więc wymyśliłem to:
app / models / problems / save_without_callbacks.rb
w dowolnym modelu:
wtedy możesz:
lub
źródło
Dlaczego miałbyś chcieć móc to robić podczas programowania? Z pewnością będzie to oznaczać, że tworzysz aplikację z nieprawidłowymi danymi i jako taka będzie zachowywała się dziwnie, a nie tak, jak oczekujesz w produkcji.
Jeśli chcesz zapełnić swoją bazę deweloperską danymi, lepszym podejściem byłoby zbudowanie zadania prowizji, które wykorzystywało fałszywy klejnot do zbudowania prawidłowych danych i zaimportowanie ich do bazy danych, tworząc tyle rekordów, ile chcesz, ale jeśli jesteś na pięcie pochyliłem się nad tym i mam dobry powód Myślę, że update_without_callbacks i create_without_callbacks będą działać dobrze, ale kiedy próbujesz zgiąć szyny zgodnie ze swoją wolą, zapytaj siebie, masz dobry powód i czy to, co robisz, jest naprawdę dobrym pomysłem.
źródło
Jedną z opcji jest posiadanie oddzielnego modelu takich manipulacji przy użyciu tej samej tabeli:
(To samo podejście może ułatwić omijanie walidacji)
Stephan
źródło
Innym sposobem byłoby użycie haków walidacji zamiast wywołań zwrotnych. Na przykład:
W ten sposób możesz domyślnie uzyskać do_something, ale możesz łatwo nadpisać to:
źródło
Coś, co powinno działać ze wszystkimi wersjami
ActiveRecord
bez w zależności od opcji lub metod activerecord, które mogą istnieć lub nie.TLDR: użyj „innego modelu aktywnego rekordu” w tej samej tabeli
źródło
W przypadku niestandardowych wywołań zwrotnych użyj
attr_accessor
iunless
w wywołaniu zwrotnym.Zdefiniuj swój model w następujący sposób:
A następnie, jeśli chcesz zapisać rekord bez uderzania w
after_save
zdefiniowane wywołania zwrotne, ustawskip_after_save_callbacks
atrybut wirtualny natrue
.źródło
Nie jest to najczystszy sposób, ale możesz opakować kod wywołania zwrotnego w warunku, który sprawdza środowisko Railsów.
źródło