Chiedere se esiste un plug-in o il modo migliore per impostare una classe ActiveRecord in modo che, ad esempio, quando un record entri nello stato "pubblicato", alcuni attributi vengono congelati che non potevano essere manomessi.Rails ActiveRecord: blocco degli attributi quando il record entra in uno stato particolare
risposta
È possibile bloccare un intero oggetto AR :: B impostando @readonly su true (in un metodo), ma questo bloccherà tutti gli attributi.
Il modo in cui mi sento di raccomandare è di definire i metodi attributo setter che controllano lo stato attuale prima di passare a super:
class Post < ActiveRecord::Base
def author=(author)
super unless self.published?
end
def content=(content)
super unless self.published?
end
end
[EDIT] O per una grande quantità di attributi:
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
Che ovviamente vorrei inserire in un plug-in per condividere con altri, e aggiungere un bel DSL per l'accesso come: disable_attributes :author, :content, :comments, :when => :published?
Si potrebbe aggiungere ac convalida di ustom per bloccare le modifiche agli attributi se ti trovi in un determinato stato. È possibile codificare direttamente le cose direttamente nella convalida. Ma preferisco l'approccio un po 'più robusto usando le costanti che definiscono una lista bianca (lista di attributi che possono cambiare in uno stato) o una lista nera (lista di attributi che non possono cambiare in uno stato).
Ecco un esempio di entrambi gli approcci. Ogni approccio presuppone che ci sia un metodo di stato nel modello che restituisce lo stato corrente/nuovo come una stringa.
White List Approccio
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
approccio nero Lista
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
Dopo aver pubblicato, mi sono reso conto che la mia soluzione era essenzialmente simile a questa, tranne che scritta in modo diverso. Credo che il mio sia più esplicito, ma anche questo è positivo, in quanto è più dichiarativo. –
EmFi - grazie per la risposta.Questo è un po 'avanzato per la mia conoscenza di Ruby, in termini di due linee che coinvolgono la singola e commerciale, non sono sicuro di cosa stia succedendo lì, a meno che questo non sia inteso come un && - In realtà sto ricevendo un errore testando questo: metodo indefinito ' & 'per {}: Hash –
& è l'operatore di intersezione per gli array. http://ruby-doc.org/core/classes/Array.html#M002212. Array A & Array B restituisce gli elementi comuni a entrambi gli array. Se A & B == A allora tutti gli elementi di A sono in B. Inoltre stai ricevendo l'errore a causa di un mio errore tipografico che è stato copiato e incollato più volte. Tutte le istanze di modifiche dovrebbero essere cambiate. Ho aggiornato la soluzione per riflettere questo – EmFi
Editing attributi che non deve essere modificato è un errore di convalida:
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 usa le estensioni ActiveRecord::Dirty introdotte in 2.2 circa.
Grazie per il feedback François, questo sembra un altro ottimo modo per farlo. –
Se lo stato particolare è semplicemente persisted?
, quindi attr_readonly
è l'opzione migliore.
attr_readonly
(*attributes)
pubblico
Attributes listed as readonly will be used to create a new record but update operations will ignore these fields.
Per testare (per gentile concessione di 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. Query activerecord Rails confrontando due attributi dello stesso record
- 2. Rails ActiveRecord - Ricerca su più attributi
- 3. Aggiornamento di più record in una transazione ActiveRecord in Rails
- 4. Richiamata per attributi ActiveRecord modificati?
- 5. Inclusione degli attributi virtuali di un modello durante la conversione di un record in JSON in Rails
- 6. attività degli utenti Entra ROR
- 7. Rails: sovrascrivere il metodo di associazione ActiveRecord
- 8. Vagrant entra in stato di interruzione durante l'aggiornamento apt-get
- 9. Come utilizzare ActiveRecord in uno script rubino all'esterno di Rails?
- 10. Inserimento di record in blocco nella tabella dei record attivi
- 11. Upsert in Rails ActiveRecord
- 12. Rails ActiveRecord - come recuperare i record tra due date
- 13. Modifica updated_at in un record Rails
- 14. Quando un oggetto fittizio entra nello stato di riproduzione?
- 15. Come inizializzare i valori degli attributi 'attr_accessor'?
- 16. Validazione degli attributi virtuali in Ruby on Rails
- 17. Quando il dispositivo Android entra in modalità di sospensione?
- 18. Campo temporale database Rails/Activerecord
- 19. Inserimento o incremento atomico in ActiveRecord/Rails
- 20. Come creare il modello senza tabulazione ActiveRecord in Rails 3
- 21. Rails ActiveRecord Model Linked List
- 22. Come mantenere l'ordine per gli attributi nidificati quando si utilizza accepts_nested_attributes_for in un'applicazione Rails
- 23. Come si crea un valore predefinito per gli attributi nel modello di Rails activerecord?
- 24. ActiveRecord: l'eliminazione di record associati
- 25. Nomi attributi umani in Rails 3.x?
- 26. Ottieni attributi specifici da un modello ActiveRecord
- 27. Come toccare più record in ActiveRecord?
- 28. Come evitare eccezioni ActiveRecord :: RecordNotFound quando si interroga più record
- 29. Rails 3 Come posso consentire il passaggio degli attributi nidificati senza la designazione _attributes
- 30. Elenco degli attributi PropertyGrid
Grazie per il feedback Colin. Per un gran numero di attributi suppongo che potrei fare un'eval class per sovrascrivere questi setter passando una serie di attributi che devono essere bloccati, eh? –
Precisamente. Ho discusso se scriverlo come un class_eval, ma ho deciso contro la leggibilità. Lo affronterò anche se per gli altri. –