Rails: forcer la chaîne vide à NULL dans la base de données
y a-t-il un moyen facile (c'est-à-dire une configuration) pour forcer ActiveRecord à enregistrer les chaînes vides comme NULL dans la base de données (si la colonne le permet)?
la raison en est que si vous avez une colonne de chaîne de caractères NULL dans la base de données sans valeur par défaut, les nouveaux enregistrements qui ne positionnent pas cette valeur contiendront NULL, tandis que les nouveaux enregistrements qui positionnent cette valeur sur la chaîne vide ne seront pas NULL, conduisant à des incohérences dans la base de données que j'aimerais éviter.
aujourd'hui je suis en train de faire des trucs comme ça dans Mes modèles:
before_save :set_nil
def set_nil
[:foo, :bar].each do |att|
self[att] = nil if self[att].blank?
end
end
qui fonctionne mais n'est pas très efficace ou SECS. Je pourrais intégrer ceci dans une méthode et le mélanger dans ActiveRecord, mais avant de suivre cette voie, j'aimerais savoir s'il y a déjà un moyen de le faire.
7 réponses
Essayer si ce petit bijou fonctionne:
https://github.com/rubiety/nilify_blanks
fournit un cadre pour sauvegarder les valeurs Vierges entrantes comme nul dans la base de données dans les cas où vous préféreriez utiliser DB NULL plutôt qu'une simple chaîne blanche...
dans les Rails lors de l'enregistrement d'un modèle à partir d'une forme et les valeurs ne sont pas fournies par l'utilisateur, une chaîne vide est enregistrée dans la base de données au lieu D'un nul comme beaucoup préféreraient (mélange des blancs et des NULLs peut devenir source de confusion). Ce plugin vous permet de spécifier une liste d'attributs (ou d'exceptions de tous les attributs) qui seront convertis en nil s'ils sont vides avant qu'un modèle soit sauvegardé.
seuls les attributs répondant à blanc? avec une valeur true seront convertis à néant. Par conséquent, cela ne fonctionne pas avec des champs entiers avec la valeur de 0, par exemple...
Oui, la seule option pour le moment est d'utiliser une fonction de rappel.
before_save :normalize_blank_values
def normalize_blank_values
attributes.each do |column, value|
self[column].present? || self[column] = nil
end
end
Vous pouvez convertir le code dans un mixin d'inclure facilement dans plusieurs modèles.
module NormalizeBlankValues
extend ActiveSupport::Concern
included do
before_save :normalize_blank_values
end
def normalize_blank_values
attributes.each do |column, value|
self[column].present? || self[column] = nil
end
end
end
class User
include NormalizeBlankValues
end
Ou vous pouvez le définir dans ActiveRecord::Base à avoir dans tous vos modèles.
enfin, vous pouvez également l'inclure dans ActiveRecord::Base mais l'activer si nécessaire.
module NormalizeBlankValues
extend ActiveSupport::Concern
def normalize_blank_values
attributes.each do |column, value|
self[column].present? || self[column] = nil
end
end
module ClassMethods
def normalize_blank_values
before_save :normalize_blank_values
end
end
end
ActiveRecord::Base.send(:include, NormalizeBlankValues)
class User
end
class Post
normalize_blank_values
# ...
end
ma suggestion:
# app/models/contact_message.rb
class ContactMessage < ActiveRecord::Base
include CommonValidations
include Shared::Normalizer
end
# app/models/concerns/shared/normalizer.rb
module Shared::Normalizer
extend ActiveSupport::Concern
included do
before_save :nilify_blanks
end
def nilify_blanks
attributes.each do |column, value|
# ugly but work
# self[column] = nil if !self[column].present? && self[column] != false
# best way
#
self[column] = nil if self[column].kind_of? String and self[column].empty?
end
end
end
une autre option est de fournir des setters personnalisés, au lieu de gérer cela dans un crochet. E. g.:
def foo=(val)
super(val == "" ? nil : val)
end
Désolé pour necroposting, mais je n'ai pas trouver exactement ce que ici dans les réponses, si vous avez besoin d'une solution de spécifier champs qui doivent être nilifiés:
module EnforceNil
extend ActiveSupport::Concern
module ClassMethods
def enforce_nil(*args)
self.class_eval do
define_method(:enforce_nil) do
args.each do |argument|
field=self.send(argument)
self.send("#{argument}=", nil) if field.blank?
end
end
before_save :enforce_nil
end
end
end
end
ActiveRecord::Base.send(:include, EnforceNil)
comme Ceci:
class User
enforce_nil :phone #,:is_hobbit, etc
end
appliquer certains champs est pratique lorsque vous avez field1 et field2. Field1 a un index unique en SQL, mais peut être vide, donc vous avez besoin d'exécution (NULL considéré unique, "" - pas par SQL), mais pour field2 vous ne vous souciez pas réellement et vous avez déjà des douzaines de rappels ou les méthodes de travail lors de la champ2 est ", mais aussi de creuser votre application sous la couche d'erreurs si champ2 nil
. Situation, je pose.
Peut être utile pour quelqu'un.
j'utilise l'attribut normalisateur gem à normaliser les attributs de l'avant dans la db.
Bande Attributs Gem
il y a un petit bijou pratique qui fait cela automatiquement lors de la sauvegarde d'un enregistrement, que ce soit sous forme d'utilisateur ou dans la console ou dans une tâche de ratissage, etc.
Ça s'appelle strip_attributes et est extrêmement facile à utiliser, avec des valeurs par défaut saines, tout droit sorti de la boîte.
Il fait deux choses principales par défaut qui doit presque toujours faire:
Bande d'attaque et de fuite des blancs:
" My Value " #=> "My Value"
Tourner à vide les Chaînes en
NULL
:"" #=> NULL " " #=> NULL
Installer
Vous pouvez l'ajouter à votre bijou fichier:
gem strip_attributes
Utilisation
ajoutez - le à n'importe quel (ou tous) modèle que vous voulez rayer de l'espace principal/arrière et transformer les chaînes vides en NULL
:
class DrunkPokerPlayer < ActiveRecord::Base
strip_attributes
end
Utilisation Avancée
il y a des options supplémentaires que vous pouvez passer sur une base par modèle pour gérer les exceptions, comme si vous voulez conserver l'espace blanc menant/suivant ou non, etc.
Vous pouvez voir toutes les options sur le dépôt GitHub ici: