Ich habe ein Benutzermodell mit dem Attribut: Credits. Ich möchte eine einfache Schaltfläche, die den Credits des Benutzers 5 über eine Route mit dem Namen "add" hinzufügt, sodass / users / 3 / add 5 Credits der Benutzer-ID = 3 hinzufügt.
def add
@user = User.find(params[:id])
@user.credits += 5
redirect_to root_path
end
Das ist der relevante Teil meines Controllers. Das Problem ist, dass ich @ user.save nicht aufrufen möchte, da ich einen before_save-Rückruf habe, der das Kennwort des Benutzers basierend auf der aktuellen UTC-Zeit neu verschlüsselt. Ich möchte einfach nur 5 zum Attribut hinzufügen und den Rückruf vermeiden. Ich hätte nie gedacht, dass so eine einfache Sache so schwer sein könnte.
BEARBEITEN:
Ich habe den Rückruf geändert in: before_create, hier ist mein neuer Controller-Code (relevanter Teil):
def add
@user = User.find(params[:id])
@user.add_credits(5)
@user.save
flash[:success] = "Credits added!"
redirect_to root_path
end
und hier ist mein Code im Modell:
def add_credits(num)
self.credits = num
end
EDIT 2:
Ok, es war ein Validierungsproblem, das dazu führte, dass die Änderungen in "EDIT" nicht funktionierten, aber ich würde trotzdem gerne eine Antwort auf die ursprüngliche Frage der Aktualisierung ohne Rückrufe erhalten!
quelle
Antworten:
Rails 3.1 eingeführt
update_column
, das ist das gleiche wieupdate_attribute
, aber ohne Validierungen oder Rückrufe auszulösen:http://apidock.com/rails/ActiveRecord/Persistence/update_column
quelle
Als allgemeine Antwort ist dies in Rails 4 eine einfache Möglichkeit, Attribute zu aktualisieren, ohne Rückrufe auszulösen:
@user.update_column 'credits', 5
Wenn Sie mehrere Attribute aktualisieren müssen, ohne Rückrufe auszulösen:
@user.update_columns credits: 5, bankrupt: false
Es gibt andere Optionen hier in den Rails Guides, wenn Sie es vorziehen, aber ich fand diesen Weg am einfachsten.
quelle
UPDATE "users" SET "credits" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["credits", 5], ["updated_at", "2017-04-01 21:34:52.746626"], ["id", 1]]
Um mehrere Attribute ohne Rückruf zu aktualisieren, können Sie update_all in Ihrem Modell folgendermaßen verwenden:
self.class.update_all({name: value, name: value}, self.class.primary_key => id)
Wenn Sie wirklich möchten, können Sie sogar eine update_columns-Methode ausprobieren und diese mit Ihrer aktiven Datensatzbasisklasse mischen.
Um ein Attribut zu aktualisieren, können Sie update_column verwenden. Darüber hinaus finden Sie einige spezifische Methoden in den Schienenhandbüchern http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
quelle
Für Mongoid habe ich schließlich http://mongoid.org/en/mongoid/docs/persistence.html verwendet. Insbesondere können Sie Folgendes verwenden:
person.set(name:"Robert Pulson")
und es wird kein Rückruf ausgegeben. So cool.
quelle
Ich denke, Sie sollten in diesem Fall die Methode update_counters verwenden . Verwenden Sie es so in Ihrer Controller-Aktion:
def add User.update_counters params[:id], :credits => 5 redirect_to root_path end
quelle
Sie sollten update_all verwenden können , um das Auslösen von Rückrufen zu vermeiden.
def add @user = User.find(params[:id]) User.where(:id=>@user.id).update_all(:credits => @user.credits+5) redirect_to root_path end
Ich würde es vorziehen, diese Logik in das Modell aufzunehmen, aber dies sollte funktionieren, um Ihr ursprüngliches Problem zu lösen, wie es in der Steuerung angegeben ist.
quelle
Einige Optionen dazu in Rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
quelle
Möglicherweise sollte Ihr anderer before_save-Hook prüfen, ob sich das Kennwort des Benutzers tatsächlich geändert hat, bevor Sie es erneut verschlüsseln.
quelle
Sie haben eine Reihe von Optionen, einschließlich der Änderung des von Ihnen verwendeten Rückrufs, z
after_create
.Sie können Spalten aktualisieren, ohne Rückrufe auszulösen (siehe Überspringen von Rückrufen im AR-Handbuch). Löst beispielsweise
update_column
keine Rückrufe aus. Der vorherige Link listet nicht auslösende Funktionen auf.Sie können auch eines der bedingten Rückrufformulare (oder sogar einen Beobachter) verwenden, wenn das Kennwort geändert wird. Siehe ActiveModel :: Dirty , z
@user.password_changed?
.quelle
save!
Sie diese Option, um festzustellen, ob eine Ausnahme vorliegt (und / oder überprüfen Sie die Protokolle und / oder entfernen Sie die Schalldämpfer für die Rückverfolgung).Sie können dabei eine Spalte aktualisieren
quelle