Comment créer une valeur par défaut pour les atsortingbuts du modèle Rails activerecord?

Je veux créer une valeur par défaut pour un atsortingbut en le définissant dans ActiveRecord. Par défaut, chaque fois que l’enregistrement est créé, je souhaite avoir une valeur par défaut pour l’atsortingbut :status . J’ai essayé de faire ça:

 class Task < ActiveRecord::Base def status=(status) status = 'P' write_attribute(:status, status) end end 

Mais lors de la création, je récupère toujours cette erreur de la firebase database:

 ActiveRecord::StatementInvalid: Mysql::Error: Column 'status' cannot be null 

Par conséquent, je présume que la valeur n’a pas été appliquée à l’atsortingbut.

Quelle serait la manière élégante de le faire dans Rails?

Merci beaucoup.

Vous pouvez définir une option par défaut pour la colonne dans la migration

 .... add_column :status, :ssortingng, :default => "P" .... 

OU

Vous pouvez utiliser un callback, before_save

 class Task < ActiveRecord::Base before_save :default_values def default_values self.status ||= 'P' # note self.status = 'P' if self.status.nil? might be safer (per @frontendbeauty) end end 

Étant donné que j’ai rencontré ce problème il y a quelques instants et que les options de Rails 3.0 sont un peu différentes, je vais vous donner une autre réponse à cette question.

Dans Rails 3.0, vous voulez faire quelque chose comme ceci:

 class MyModel < ActiveRecord::Base after_initialize :default_values private def default_values self.name ||= "default value" end end 

Vous pouvez le faire sans écrire de code du tout 🙂 Il vous suffit de définir la valeur par défaut de la colonne dans la firebase database. Vous pouvez le faire dans vos migrations. Par exemple:

 create_table :projects do |t| t.ssortingng :status, :null => false, :default => 'P' ... t.timestamps end 

J’espère que cela pourra aider.

Lorsque j’ai besoin de valeurs par défaut, c’est généralement pour les nouveaux enregistrements avant que la vue de la nouvelle action ne soit rendue. La méthode suivante définira les valeurs par défaut pour les nouveaux enregistrements uniquement afin qu’ils soient disponibles lors du rendu des formulaires. before_save et before_create sont trop tard et ne fonctionneront pas si vous voulez que les valeurs par défaut apparaissent dans les champs de saisie .

 after_initialize do if self.new_record? # values will be available for new record forms. self.status = 'P' self.featured = true end end 

La solution dépend de quelques choses.

La valeur par défaut dépend-elle d’autres informations disponibles au moment de la création? Pouvez-vous effacer la firebase database avec des conséquences minimales?

Si vous avez répondu oui à la première question, alors vous voulez utiliser la solution de Jim

Si vous avez répondu oui à la deuxième question, alors vous voulez utiliser la solution de Daniel

Si vous avez répondu non à ces deux questions, vous feriez probablement mieux d’append et d’exécuter une nouvelle migration.

 class AddDefaultMigration < ActiveRecord::Migration def self.up change_column :tasks, :status, :string, :default => default_value, :null => false end end 

: ssortingng peut être remplacé par tout type reconnu par ActiveRecord :: Migration.

Le processeur est bon marché, donc la redéfinition de la tâche dans la solution de Jim ne posera pas beaucoup de problèmes. Surtout dans un environnement de production. Cette migration est une manière appropriée de le faire car elle est chargée et appelée beaucoup moins souvent.

J’envisagerais d’utiliser les attr_defaults trouvés ici . Vos rêves les plus fous se réaliseront.

Renforcer la réponse de Jim

En utilisant la présence, on peut faire

 class Task < ActiveRecord::Base before_save :default_values def default_values self.status = status.presence || 'P' end end 

Pour les types de colonne pris en charge par Rails, comme la chaîne dans cette question, la meilleure approche consiste à définir la colonne par défaut dans la firebase database elle-même, comme l’indique Daniel Kristensen. Les rails introspectent la firebase database et initialisent l’object en conséquence. De plus, votre firebase database est protégée de toute personne qui ajoute une ligne en dehors de votre application Rails et oublie d’initialiser cette colonne.

Pour les types de colonnes, Rails ne prend pas en charge les colonnes – par exemple, les colonnes ENUM – Rails ne pourra pas parsingr la colonne par défaut. Pour ces cas, vous ne voulez pas utiliser after_initialize (il est appelé à chaque fois qu’un object est chargé à partir de la firebase database et chaque fois qu’un object est créé à l’aide de .new), before_create (car il se produit après la validation) ou before_save cela se produit également lors de la mise à jour, ce qui n’est généralement pas ce que vous voulez).

Vous souhaitez plutôt définir l’atsortingbut dans une valeur before_validation sur: create, comme ceci:

 before_validation :set_status_because_rails_cannot, on: :create def set_status_because_rails_cannot self.status ||= 'P' end 

À mon avis, deux problèmes doivent être résolus lorsque vous avez besoin d’une valeur par défaut.

  1. Vous avez besoin de la valeur présente lorsqu’un nouvel object est initialisé. Utiliser after_initialize ne convient pas car, comme indiqué, il sera appelé lors des appels à #find, ce qui entraînera un impact sur les performances.
  2. Vous devez conserver la valeur par défaut lors de l’enregistrement

Voici ma solution:

 # the reader providers a default if nil # but this wont work when saved def status read_atsortingbute(:status) || "P" end # so, define a before_validation callback before_validation :set_defaults protected def set_defaults # if a non-default status has been assigned, it will remain # if no value has been assigned, the reader will return the default and assign it # this keeps the default logic DRY status = status end 

J’aimerais savoir pourquoi les gens pensent à cette approche.

J’ai trouvé une meilleure façon de le faire maintenant:

 def status=(value) self[:status] = 'P' end 

Dans Ruby, un appel de méthode ne doit pas avoir de parenthèses, par conséquent, je devrais nommer la variable locale en quelque chose d’autre, sinon Ruby le reconnaîtra comme un appel de méthode.

Dans votre exemple, vous affectez «P» à une variable locale «status». Essayez self.status = 'P' pour ce truc de roi. Bien qu’il serait préférable d’utiliser after_initialize comme mentionné dans d’autres réponses.