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.

40
demandé sur Thilo 2011-08-26 12:59:46

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...

19
répondu dexter 2016-09-23 08:29:59

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
47
répondu Simone Carletti 2012-12-31 19:30:17

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
4
répondu klay 2014-09-23 18:41:51

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
4
répondu troelskn 2016-03-19 13:08:55

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.

2
répondu Joe Half Face 2017-01-19 12:10:23

j'utilise l'attribut normalisateur gem à normaliser les attributs de l'avant dans la db.

0
répondu daslicious 2016-10-10 23:44:20

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:

  1. Bande d'attaque et de fuite des blancs:

    " My Value " #=> "My Value"
    
  2. 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:

https://github.com/rmm5t/strip_attributes#examples

0
répondu Joshua Pinter 2018-03-09 18:24:24