Fragen, ob es ein Plugin oder die beste Möglichkeit gibt, eine ActiveRecord-Klasse so einzurichten, dass zum Beispiel ein Datensatz in den "published" -Zustand eintritt dass sie nicht manipuliert werden könnten.Rails ActiveRecord: Sperren von Attributen, wenn Datensatz in einen bestimmten Zustand eintritt
Antwort
Sie können ein gesamtes AR :: B-Objekt einfrieren, indem Sie @readonly auf true (in einer Methode) festlegen. Dadurch werden jedoch alle Attribute gesperrt.
Die Art, wie ich empfehlen würde, ist durch Attribut Setter-Methoden definiert, die zu Super, bevor er für den aktuellen Zustand überprüfen:
class Post < ActiveRecord::Base
def author=(author)
super unless self.published?
end
def content=(content)
super unless self.published?
end
end
[EDIT] Oder für eine große Menge von Attributen:
class Post < ActiveRecord::Base
%w(author content comments others).each do |method|
class_eval <<-"end_eval", binding, __FILE__, __LINE__
def #{method}=(val)
super unless self.published?
end
end_eval
end
end
Welche würde ich befürworten ziehen in ein Plugin mit anderen zu teilen, und fügen Sie eine schöne DSL für den Zugriff wie: disable_attributes :author, :content, :comments, :when => :published?
Sie könnten ac hinzufügen ustom-Validierung, um Änderungen an Attributen zu blockieren, wenn Sie sich in einem bestimmten Status befinden. Sie könnten Dinge direkt in die Validierung einprogrammieren. Aber ich bevorzuge den leicht robusteren Ansatz mit Konstanten, die eine Whitelist definieren (eine Liste von Attributen, die sich in einem Zustand ändern dürfen) oder eine Blacklist (Liste von Attributen, die sich in einem Zustand nicht ändern dürfen).
Hier ist ein Beispiel für beide Ansätze. Bei jedem Ansatz wird davon ausgegangen, dass in Ihrem Modell eine Statusmethode vorhanden ist, die den aktuellen/neuen Status als Zeichenfolge zurückgibt. Ansatz
White List
WhiteListStateLockMap = {
"state_1" => [
"first_attribute_allowed_to_change_in_state_1",
"second_attribute_allowed_to_change_in_state_1",
...
],
"state_2" => [
"first_attribute_allowed_to_change_in_state_2",
"second_attribute_allowed_to_change_in_state_2",
...
],
...
}
validates :state_lock
def state_lock
# ensure that all changed elements are on the white list for this state.
unless changed & WhiteListStateLockMap[state] == changed
# add an error for each changed attribute absent from the white list for this state.
(changed - WhiteListStateLockMap[state]).each do |attr|
errors.add attr, "Locked while #{state}"
end
end
end
Black List Ansatz
BlackListStateLockMap = {
"state_1" => [
"first_attribute_not_allowed_to_change_in_state_1,
"second_attribute_not_allowed_to_change_in_state_1,
...
],
"state_2" => [
"first_attribute_not_allowed_to_change_in_state_2",
"second_attribute_not_allowed_to_change_in_state_2",
...
],
...
}
validates :state_lock
def state_lock
# ensure that no changed attributes are on the black list for this state.
unless (changed & BlackListStateLockMap[state]).empty?
# add an error for all changed attributes on the black list for this state.
(BlackListStateLockMap[state] & changed).each do |attr|
errors.add attr, "Locked while #{state}"
end
end
end
Nachdem ich geschrieben hatte, erkannte ich, dass meine Lösung im Wesentlichen ähnlich zu dieser war, außer anders geschrieben. Ich glaube, meine ist expliziter, aber das ist auch gut, weil es deklarativer ist. –
EmFi - danke für die Antwort.Dies ist etwas fortgeschritten für mein Ruby-Wissen, in Bezug auf die zwei Linien, die das einzelne Ampersand betreffen, nicht sicher, was genau dort passiert, es sei denn, dies ist ein && - Ich erhalte tatsächlich einen Fehler beim Testen: undefinierte Methode & 'for {}: Hash –
& ist der Schnittmengenoperator für Arrays. http://ruby-doc.org/core/classes/Array.html#M002212. Array A & Array B gibt die für beide Arrays gemeinsamen Elemente zurück. Wenn A und B == A sind, dann sind alle Elemente von A in B. Außerdem erhalten Sie den Fehler wegen eines Tippfehlers, der mehrmals kopiert und eingefügt wurde. Alle Instanzen von Änderungen sollten sich geändert haben. Ich habe die Lösung aktualisiert, um dies zu reflektieren – EmFi
Bearbeiten Attribute, die nicht bearbeitet werden sollte ein Überprüfungsfehler ist:
class Post < ActiveRecord::Base
validate :lock_down_attributes_when_published
private
def lock_down_attributes_when_published
return unless published?
message = "must not change when published"
errors.add(:title, message) if title_changed?
errors.add(:published_at, message) if published_at_changed?
end
end
Thi s verwendet die in 2.2 oder so eingeführten Erweiterungen ActiveRecord::Dirty.
Danke für das Feedback François, sieht dies wie eine andere gute Möglichkeit, dies zu tun. –
Wenn der bestimmte Zustand nur persisted?
ist, dann ist attr_readonly
die beste Option.
attr_readonly
(*attributes)
öffentliche
Attributes listed as readonly will be used to create a new record but update operations will ignore these fields.
Um zu testen (mit freundlicher Genehmigung von THAiSi):
class MyModel < ActiveRecord::Base
attr_readonly :important_type_thingie
end
#RSpec
describe MyModel do
its('class.readonly_attributes') { should include "important_type_thingie" }
it "should not update the thingie" do
m = create :my_model, :important_type_thingie => 'foo'
m.update_attributes :important_type_thingie => 'bar'
m.reload.important_type_thingie.should eql 'foo'
end
end
- 1. Rails ActiveRecord - Suche nach mehreren Attributen
- 2. Rails 5 Beta 3 ActiveRecord Datensatz ungültig
- 3. Rails: einen asynchronen Datensatz schreiben
- 4. ActiveRecord create: übergeben in einem Array von Attributen
- 5. Verlassen von einer make-Datei, wenn der Zustand von zwei Shell-Variablen einen bestimmten Zustand
- 6. ActiveRecord, außer einem Datensatz! =?
- 7. Rails Finden Sie einen Datensatz in ActiveRecord :: Relation Object ohne erneut Datenbank abzufragen
- 8. Müssen ActiveRecord-Sperren innerhalb einer Transaktion ausgeführt werden?
- 9. Rails 4 ActiveRecord undefined Methode
- 10. Rails/ActiveRecord - AdapterNotSpecified, auch wenn es
- 11. Upsert in Rails ActiveRecord
- 12. Aktiver Datensatz. Einen "Besuch" Zähler mit Ruby on Rails
- 13. Wählen Sie Sperren in Rails mit MySQL
- 14. eintritt, wenn tk_messageBox in tcl erscheint
- 15. Rails ActiveRecord Erstellen oder Suchen
- 16. Sortieren von ActiveRecord-Objekten in Rails 3
- 17. Gibt zwei ActiveRecord-Abfragen einen Datensatz als dasselbe Objekt zurück?
- 18. Löschen Sie keine Impressions, wenn Sie einen Datensatz löschen
- 19. Can Rails ActiveRecord #save Methode verwendet werden, um einen bestehenden Datensatz zu aktualisieren?
- 20. atomisches Einfügen oder Inkrementieren in ActiveRecord/Rails
- 21. In ActiveRecord von Rails, wofür ist Touch?
- 22. Ruby on Rails: ActiveRecord :: AssociationTypeMismatch
- 23. Rails ActiveRecord: HABTM Parameter finden
- 24. -Datensatz erstellen, basierend auf Zustand
- 25. Apache Schwein. einen bestimmten Datensatz erhalten
- 26. explizit sperren Zeile beim Aktualisieren von Datensatz in Mysql
- 27. Rails: ActiveRecord benutzerdefinierte Durchschnittsberechnung
- 28. Rails ActiveRecord-Beziehungen
- 29. vorbereitete Anweisungen in rails/activerecord
- 30. gründliche Anleitung zu Sperren/Transaktionen/Isolation Levels in Rails
Danke für das Feedback Colin. Für eine große Anzahl von Attributen nehme ich an, dass ich eine Klasse eval machen könnte, um diese Setter zu überschreiben, indem ich ein Array von Attributen übergebe, die gesperrt werden müssen, wie? –
Genau. Ich überlegte, ob ich es als class_eval schreiben sollte, entschied mich aber aus Gründen der Lesbarkeit dagegen. Ich werde es aber für andere angehen. –