Schienen 3 überspringen Validierungen und Rückrufe

72

Ich habe ein besonders komplexes Modell mit definierten Validierungen und Rückrufen. Die geschäftlichen Anforderungen erfordern jetzt ein bestimmtes Szenario, in dem das Hinzufügen eines neuen Datensatzes das Überspringen der Validierungen und Rückrufe erfordert. Was ist der beste Weg, dies zu tun?

Johnny Klassy
quelle

Antworten:

118

Dies funktioniert in Rails 3:

Model.skip_callback(:create)
model.save(:validate => false)
Model.set_callback(:create)

( API-Dokumente und verwandte Fragen )

Dinatih
quelle
5
Müssen Sie nicht noch einmal verwenden set_callback(:create)? Ich hatte den Eindruck, dass es skip_callbackdeaktiviert wird, bis es wieder aktiviert wird.
Caley Woods
1
Ich denke ja, ich benutze diese Methode nie, mehr Infos api.rubyonrails.org/classes/ActiveSupport/Callbacks/…
Dinatih
20
Das kann nicht threadsicher sein? Es wäre schön, es auf Instanzebene einstellen zu können.
Christopher Lindblom
1
Nur für den Fall, dass jemand das gleiche Problem hat wie ich: In Schienen 3 wurden die Beobachter-Rückrufe nicht deaktiviert. Um das zu tun, habe ich getan, was stackoverflow.com/questions/707615/… sagt
Alex Siri
Vor kurzem haben wir das Problem in unserem Projekt. Wir haben dies mit einem ziemlich einfachen Ansatz gelöst. Es funktioniert bei uns gut. Die Lösung ist für jede Version von Rails. Überprüfen Sie es in meinem Blog-Beitrag: railsguides.net/2014/03/25/skip-callbacks-in-tests
ka8725
29

Verwenden Sie ActiveRecord :: Persistence # update_column wie folgt :

Model.update_column(field, value)
Bowsersenior
quelle
Gemäß der von Ihnen verlinkten Dokumentation: "Rückrufe werden aufgerufen."
Eggie5
5
Ich denke, Sie haben in der Dokumentation nachgesehen update_attribute, nicht nach update_column. Wenn Sie sich die Dokumentation ansehen update_column, entspricht dies update_columnseiner einzelnen Spalte. In den Dokumenten wird update_columnseindeutig angegeben, dass Validierungen und Rückrufe übersprungen werden.
Bowsersenior
Rette mein leben! Ich habe skip_callback und andere Methoden ausprobiert, kein Glück. Das funktioniert!
Chihung Yu
10

Wenn das Ziel darin besteht, einfach einen Datensatz ohne Rückrufe oder Überprüfungen einzufügen oder zu aktualisieren, und Sie dies tun möchten, ohne auf zusätzliche Edelsteine ​​zurückzugreifen, bedingte Überprüfungen hinzuzufügen, RAW SQL zu verwenden oder in irgendeiner Weise mit Ihrem Beendigungscode zu fummeln, kann dies der Fall sein Es ist möglich, ein "Schattenobjekt" zu verwenden, das auf Ihre vorhandene DB-Tabelle verweist. Wie so:

class ImportedUser < ActiveRecord::Base
  # To import users with no validations or callbacks
  self.table_name = 'users'
end

Dies funktioniert mit jeder Version von Rails, ist threadsicher und eliminiert alle Validierungen und Rückrufe vollständig, ohne Änderungen an Ihrem vorhandenen Code vorzunehmen. Denken Sie daran, Ihre neue Klasse zum Einfügen des Objekts zu verwenden, z.

ImportedUser.new( person_attributes )
Brad Werth
quelle
1
das ist so schlau. hat mir Kopfschmerzen erspart!
Tim Kretschmer
2

Meine Einstellung war wie folgt (Hinweis: Dadurch werden Rückrufe beim Erstellen, Aktualisieren, Löschen und andere deaktiviert, die Sie zum Array hinzufügen müssen).

    begin
      [:create, :save].each{|a| self.class.skip_callback(a) } # We disable callbacks on save and create

      # create new record here without callbacks, tou can also disable validations with 
      # .save(:validate => false)
    ensure
      [:create, :save].each{|a| self.class.set_callback(a) }  # and we ensure that callbacks are restored
    end
Marcin Raczkowski
quelle
Upvoted, aber dann hat es für meine 3.2.6 App nicht funktioniert. Ich habe Model.skip_callback (: create ,: after)
TuteC
Dies ist eine Lösung für 3.0+. Es wird nicht für 2.x funktionieren - aber ich erinnere mich, als ich nach einer Lösung für dieses Problem suchte, bin ich auf eine Lösung für 2.x gestoßen, die für 3.x nicht funktioniert hat
Marcin Raczkowski
2

Ich würde empfehlen, den skip_callback-Ansatz NICHT zu verwenden, da er nicht threadsicher ist. Das hinterhältige Juwel ist jedoch, dass es nur gerade SQL läuft. Beachten Sie, dass dies keine Validierungen auslöst, sodass Sie sie selbst aufrufen müssen (z. B. my_model.valid?).

Hier sind einige Beispiele aus ihren Dokumenten:

# Update. Returns true on success, false otherwise.
existing_record.sneaky_save

# Insert. Returns true on success, false otherwise.
Model.new.sneaky_save

# Raise exception on failure.
record.sneaky_save!
Eric
quelle
1

Wie wäre es, wenn Sie Ihrem Modell eine Methode hinzufügen, mit der Sie die Rückrufe überspringen können?

class Foo < ActiveRecord::Base
  after_save :do_stuff

  def super_secret_create(attrs)
    self.skip_callback(:create)
    self.update_attributes(attrs)
    self.save(:validate => false)
    self.set_callback(:create)
  end
end

Wenn Sie am Ende so etwas verwenden, würde ich empfehlen, self in der Methode anstelle des Modellnamens zu verwenden, um die Konnotation des Namens zu vermeiden.

Ich bin auch auf einen Kern von Sven Fuchs gestoßen, der gut aussieht, er ist hier

Caley Woods
quelle
1
Ich mag diesen Ansatz, werde aber skip_callbackals Klassenmethode angezeigt, während update_attributeses sich um eine Instanzmethode handelt. Haben Sie das beabsichtigt? Hmm, ich verstehe es nicht, das API-Dokument sagt, es skip_callbacksei eine Instanzmethode, aber es ist nicht so in der Rails-Konsole, seltsam.
Johnny Klassy
1

Ich habe ein einfaches Juwel geschrieben, um Validierungen adhoc zu überspringen, aber es könnte wahrscheinlich aktualisiert werden, um auch das Überspringen von Rückrufen einzuschließen.

https://github.com/npearson72/validation_skipper

Sie können das can_skip_validation_forin den Edelstein nehmen und Funktionen hinzufügen, um auch Rückrufe zu überspringen. Vielleicht die Methode aufrufencan_skip_validation_and_callbacks_for

Alles andere würde gleich funktionieren. Wenn Sie dabei Hilfe benötigen, lassen Sie es mich wissen.

Nathan
quelle
0

Dieser Hack hat endlich bei mir funktioniert (neu definierte _notify_comment_observer_for_after_createMethode für das Objekt):

if no_after_create_callback
  def object._notify_comment_observer_for_after_create; nil; end
end
TuteC
quelle
0

Keines davon funktioniert, wenn Ihre Validierungen in die Datenbank selbst geschrieben werden.

+------------------------------------+--------------------------------------------------+------+-----+--------------------+----------------+
| Field                              | Type                                             | Null | Key | Default            | Extra          |
+------------------------------------+--------------------------------------------------+------+-----+--------------------+----------------+
| status                             | enum('Big','Small','Ugly','Stupid','Apologetic') | NO   |     | Stupid             |                |
Joshua Cook
quelle