Est-il un moyen facile de faire un Rails de ActiveRecord modèle en lecture seule?
Je veux être en mesure de créer un enregistrement dans la DB mais alors prévenir les Rails d'apporter des modifications à partir de ce point. Je comprends modifications seront encore possibles au niveau de DB.
Je crois attr_readonly fait ce que je veux sur un attribut de niveau, mais je ne veux pas avoir à spécifier manuellement les champs... je préférerais avoir plus d'une liste blanche d'approche.
Aussi, je sais qu'il est un :read_only option pour les associations, mais je ne veux pas limiter les "readonlyness" de l'objet si elle a été récupérée par l'intermédiaire d'une association ou non.
Enfin, je veux être en mesure de toujours détruire un enregistrement pour des trucs comme :dépendante => :détruire les œuvres dans les associations.
Donc, pour résumer: 1) permettre la création de dossiers, 2) permettre la suppression d'enregistrements, et 3) d'éviter toute modification des enregistrements qui ont été conservées.
Vous devez vous connecter pour publier un commentaire.
Regardant
ActiveRecord::Persistance
, tout finit par appelercreate_or_update
derrière les coulisses.Donc! Juste:
model.readonly!
initialize
, droit?!new_record?
au lieu depersisted?
. La raison en est quepersisted?
sera de retour false si vous actuellement en train de détruire l'objet, donc vous devriez toujours être en mesure de détruire votre lecture seule de l'objet!delete
méthode à exécuter. Selon api.rubyonrails.org/classes/ActiveRecord/...Note that this will also delete records marked as #readonly?.
J'ai trouvé un plus concis solution, qui utilise le
after_initialize
rappel:before_update :readonly!
si vous voulez empêcher la modification d'un enregistrement existant, mais encore envie de création et de suppression.Pourquoi ne pas simplement créer un utilisateur sur la base de données qui a accès en lecture seule, et ont rails utiliser ce compte.
Cependant, si vous voulez le modèle de niveau d'accès, vous pouvez ajouter ce qui suit à un modèle spécifique:
model.delete
, car cela ne déclenche pas de rappels?before_destroy
rappel de l'ajout de la fonction va conduire à la rupture et il est inutile étant donné que la première ligne dansdestroy
estraise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
Ce blog est toujours valide: http://ariejan.net/2008/08/17/activerecord-read-only-models/
Fondamentalement, vous pouvez compter sur ActiveRecord de validation si vous ajoutez une méthode:
TL;DR pour des OP
Généralement
before_create { false }
before_update { false }
before_destroy { false } # does not prevent delete
Voir aussi: http://guides.rubyonrails.org/active_record_callbacks.html
Cela semble assez efficace et est probablement un peu exagéré, mais pour mon cas, je veux vraiment être sûr que ma demande ne sera jamais de créer, d'enregistrer, de modifier ou de détruire tous les enregistrements dans le modèle, jamais.
Depuis l'OP a demandé à être en mesure de créer et de détruire, mais de ne pas enregistrer ou mettre à jour je crois que cela va fonctionner
Pas exactement l'exception au droit, mais assez proche je pense.
Un validateur personnalisé peut le faire:
La recherche d'un moyen pour obtenir le même contrôle proposé par @Nate (en évitant de créer/mettre à jour/supprimer) mais en utilisant seulement dans certaines parties de mon application et pour tous les modèles à la fois, j'ai créé ce Rubis raffinement:
Et à les utiliser uniquement dans une partie spécifique du code:
(C'est un véritable cas d'utilisation, je cherchais un moyen pour éviter que les gens la création et la modification réelle des enregistrements à partir de l'intérieur de ActionMailer::Aperçus parce que je veux permettre aperçus dans la production, mais si par erreur quelqu'un crée un aperçu des modifications de données réelles, ce serait devenu un chaos).
Le code est un peu moche de redéfinir toutes les méthodes (créer, créez!, etc), parce que l'intention est de modifier le comportement de tous les modèles, et les rappels comme "before_create" ne peut pas être utilisé à cette fin car ils ne sont pas localement uniquement à la section "utilisation" de la portée, la modification de l'ensemble de l'application.
Cette approche est de travailler pour moi, je peux bloquer tout ce de méthodes pour tous les modèles dans une seule classe, et ne plaisante pas avec le reste de l'application. Malheureusement, jusqu'à maintenant, par les améliorations ne s'appliquent pas à des sous-classes, donc dans mon cas je n'ai pas été en mesure de bloquer tous les insère par défaut dans la classe parent (ActionMailer::Aperçu), ce qui était mon objectif de départ, mais le blocage par classe est un bon point de départ.
Mon application nécessite le raffinement de toutes les méthodes, mais le contrôle peut être effectué uniquement pour les méthodes intéressantes comme les détruire, ou de mettre à jour eux et cela fonctionne pour tous les cas, y compris celui de la question d'origine.