2011-12-28 7 views
52

Mam model użytkownika, który ma atrybut: credits. Chcę prosty przycisk, który będzie dodać 5 kredytów użytkownika, za pośrednictwem szlaku zwanym „dodać” tak, że/users/3/add by dodać 5 do kredytów identyfikatora użytkownika = 3.Szyny: Zaktualizuj atrybut modelu bez wywoływania wywołań zwrotnych

def add 
    @user = User.find(params[:id]) 
    @user.credits += 5 
    redirect_to root_path 
end 

To odpowiednią część mojego kontrolera. Problem polega na tym, że nie chcę wywoływać @ user.save, ponieważ mam wywołanie zwrotne before_save, które ponownie szyfruje hasło użytkownika na podstawie bieżącego czasu UTC. Chcę po prostu dodać 5 do atrybutu i uniknąć wywołania zwrotnego, nigdy nie sądziłem, że tak prosta rzecz może być tak trudna.

EDIT:

Zmieniłem oddzwanianie do: before_create, tu jest mój nowy kod kontrolera (odpowiedniej części):

def add 
    @user = User.find(params[:id]) 
    @user.add_credits(5) 
    @user.save 
    flash[:success] = "Credits added!" 
    redirect_to root_path 
    end 

i tu jest mój kod w modelu:

def add_credits(num) 
    self.credits = num 
end 

EDYCJA 2:

OK problem z potwierdzeniem które sprawiło, że zmiany w "EDYCIE" nie działają, ale nadal chciałbym odpowiedzi na oryginalne pytanie o aktualizację bez wywołań zwrotnych!

+0

Dostarczyłem łącze z listą metod, które nie wyzwalają wywołań zwrotnych, a zarówno Finbarr jak i ja zasugerowaliśmy użycie warunkowego wywołania zwrotnego - jakich dodatkowych rozwiązań szukasz? –

Odpowiedz

1

Może twój inny haczyk before_save powinien sprawdzić, czy hasło użytkownika rzeczywiście się zmieniło przed ponownym zaszyfrowaniem.

1

Masz wiele opcji, w tym zmianę używanego połączenia zwrotnego, np. after_create.

Możesz aktualizować kolumny bez wyzwalania zwrotnego, patrz Skipping Callbacks w przewodniku AR. Na przykład update_column nie wyzwala wywołań zwrotnych. Poprzedni link zawiera funkcje niezwiązane z uruchamianiem.

Można również użyć dowolnego z formularzy Conditional Callback (lub nawet obserwatora) do zmiany hasła. Zobacz ActiveModel::Dirty, np. @user.password_changed?.

+0

OK Zmieniłem go na "after_create", ale nadal nie zadziała! Zobacz moją edycję mojego nowego kodu, nie mogę otrzymać kredytów do zmiany. –

+0

@hatboysam Cóż, robi coś innego - zanim dodałeś, teraz ustawiasz. Użyj 'zapisz!', Aby sprawdzić, czy jest wyjątek (i/lub sprawdź logi i/lub usuń tłumiki cofania). –

2

Powinieneś być w stanie użyć numeru update_all, aby uniknąć wyzwalania zwrotnego.

def add 
@user = User.find(params[:id]) 
User.where(:id=>@user.id).update_all(:credits => @user.credits+5) 
redirect_to root_path 
end 

wolałbym umieścić tę logikę w modelu, ale to powinno działać, aby rozwiązać oryginalny problem jak spec''d w kontrolerze.

2

Myślę, że powinieneś użyć metody update_counters w tym przypadku. Użyj go, jak to w swoim działaniu kontrolera:

def add 
    User.update_counters params[:id], :credits => 5 
    redirect_to root_path 
end 
+0

update_counters/increment_counter również działają z 2.x ładnie! – rogerdpack

5

Aby zaktualizować wiele atrybutów bez wywołania zwrotne możesz użyć update_all w swoim modelu:

self.class.update_all({name: value, name: value}, self.class.primary_key => id) 

Jeśli naprawdę ly chcesz, możesz nawet wypróbować nawet metodę update_columns i wstawić ją do swojej aktywnej klasy bazowej rekordów.

Aby zaktualizować jeden atrybut, można użyć kolumny aktualizacyjnej. Ponadto istnieją pewne specyficzne metody, które można znaleźć w szynach prowadzi http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

+1

wreszcie odpowiedź, która działa z szynami 2.x, dziękuję! – rogerdpack

2

Dla mongoid, skończyło się za pomocą http://mongoid.org/en/mongoid/docs/persistence.html Konkretnie, można użyć:

person.set(name:"Robert Pulson") 

i nie zostanie wysłane żadne żądanie oddzwonienia. Ale fajnie.

+0

jego person.set (: nazwa "Robert Pulson") –

+1

@JudeCalimbas no nie, ArgumentError: zła ilość argumentów (biorąc pod uwagę 2, spodziewane 1) – rept

1

Jako ogólną odpowiedź, w Rails 4 Jest to prosty sposób zaktualizować atrybuty bez wyzwalania wywołania zwrotne:

@user.update_column credits:5 

Jeśli trzeba aktualizować wiele atrybutów bez wywołuje wywołania zwrotne:

@user.update_columns credits: 5, bankrupt: false 

Nie są inne opcje here in the Rails Guides jeśli wolisz, ale znalazłem w ten sposób być najłatwiejszym.

+1

kredyty user.update_column: 5 nie działa. To powinno być user.update_column "credits", 5 –

+0

Używam Rails 4.2 i to na pewno działa dla mnie. Ta linia generuje następujące zapytanie: "UPDATE" użytkownicy "SET" kredyty "= 1 $," updated_at "= 2 $ WHERE" użytkownicy "." Id "= 3 $ [[" credits ", 5], [" updated_at "," 2017 -04-01 21: 34: 52.746626 "], [" id ", 1]]" – Matt

Powiązane problemy