Rails: принудительная установка пустой строки в базу данных NULL - PullRequest
43 голосов
/ 26 августа 2011

Есть ли простой способ (т.е. конфигурация) заставить ActiveRecord сохранять пустые строки как NULL в БД (если это позволяет столбец)?

Причиной этого является то, что если в БД есть столбец строки NULLable без значения по умолчанию, новые записи, которые не задают это значение, будут содержать NULL, тогда как новые записи, которые устанавливают это значение в пустую строкуне будет NULL, что приведет к несоответствиям в базе данных, которых я хотел бы избежать.

Сейчас я делаю в своих моделях такие вещи:

before_save :set_nil

def set_nil
  [:foo, :bar].each do |att|
    self[att] = nil if self[att].blank?
  end
end

, которая работает, ноне очень эффективный или сухой.Я мог бы включить это в метод и смешать его с ActiveRecord, но прежде чем идти по этому пути, я хотел бы знать, есть ли способ сделать это уже.

Ответы [ 7 ]

49 голосов
/ 26 августа 2011

Да, единственный вариант на данный момент - использовать обратный вызов.

before_save :normalize_blank_values

def normalize_blank_values
  attributes.each do |column, value|
    self[column].present? || self[column] = nil
  end
end

Вы можете преобразовать код в миксин, чтобы легко включить его в несколько моделей.

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

Или вы можете определить его в ActiveRecord :: Base, чтобы иметь его во всех ваших моделях.

Наконец, вы также можете включить его в ActiveRecord :: Base, но включить его при необходимости.

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
19 голосов
/ 26 августа 2011

Попробуйте, если этот гем работает:

https://github.com/rubiety/nilify_blanks

Предоставляет платформу для сохранения входящих пустых значений как nil в базе данных в тех случаях, когда вы предпочитаете использовать DB NULLчем просто пустая строка ...

В Rails при сохранении модели из формы, а значения не предоставляются пользователем, пустая строка записывается в базу данных вместо NULL, как многие предпочитают (смешиваниепробелы и NULL могут привести к путанице).Этот плагин позволяет вам указать список атрибутов (или исключений из всех атрибутов), которые будут преобразованы в ноль, если они будут пустыми до сохранения модели.

Только атрибуты, отвечающие на пустое?со значением true будет преобразован в ноль.Следовательно, это не работает с целочисленными полями со значением 0, например ...

7 голосов
/ 19 марта 2016

Другим вариантом является предоставление пользовательских сеттеров вместо того, чтобы обрабатывать это в ловушкеНапример:

def foo=(val)
  super(val == "" ? nil : val)
end
4 голосов
/ 23 сентября 2014

Мое предложение:

# 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
2 голосов
/ 04 января 2016

Извините за некропостинг, но я не нашел здесь точной информации в ответах, если вам нужно решение для , укажите поля, которые следует обнулить:

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)

Таким образом:

class User
  enforce_nil :phone #,:is_hobbit, etc  
end

Применение определенного поля удобно, когда, скажем, у вас есть field1 и field2. Field1 имеет уникальный индекс в SQL, но может быть пустым, поэтому вам нужно принудительное применение (NULL считается уникальным, "" - не SQL), но для field2 вас это не волнует, и у вас уже есть десятки обратных вызовов или методов, которые работают когда field2 равно "", но будет копать ваше приложение под слоем ошибок, если field2 равно nil. Ситуация, с которой я столкнулся.

Может быть кому-нибудь пригодится.

0 голосов
/ 09 марта 2018

Полосатый атрибут Gem

Есть удобный гем, который делает это автоматически при сохранении записи, будь то в пользовательской форме, консоли или в рейке и т. Д.

Он называется strip_attributes и чрезвычайно прост в использовании, с нормальными настройками по умолчанию.

По умолчанию он выполняет две основные функции:должно почти всегда выполняться:

  1. Убрать начальные и конечные пробелы:

    " My Value " #=> "My Value"
    
  2. Превратить пустые строки вNULL:

    ""  #=> NULL
    " " #=> NULL
    

Установить

Вы можете добавить его в свой файл gem с помощью:

gem strip_attributes

Использование

Добавьте его ко всем (или всем) моделям, из которых вы хотите убрать начальные / конечные пробелы, и превратите пустые строки в NULL:

class DrunkPokerPlayer < ActiveRecord::Base
  strip_attributes
end

Расширенное использование

Существуют дополнительные опции, которые вы можете передавать для каждой модели для обработки исключений, например, если вы хотите сохранить начальный / конечный интервалили нет, и т. д.

Вы можете просмотреть все опции в репозитории GitHub здесь:

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

0 голосов
/ 11 октября 2016

Я использую гем атрибутов нормализатора для нормализации атрибутов до того, как они попадут в БД.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...