Rails:在数据库中强制将空字符串设置为NULL

Thi*_*ilo 46 mysql activerecord ruby-on-rails ruby-on-rails-3.1

是否有一种简单的方法(即配置)强制ActiveRecord在DB中将空字符串保存为NULL(如果列允许)?

这样做的原因是,如果DB中的NULLable字符串列没有默认值,则不设置此值的新记录将包含NULL,而将此值设置为空字符串的新记录将不为NULL,我希望避免的数据库中的不一致.

现在我在我的模型中做这样的事情:

before_save :set_nil

def set_nil
  [:foo, :bar].each do |att|
    self[att] = nil if self[att].blank?
  end
end
Run Code Online (Sandbox Code Playgroud)

哪个有效,但效率不高或干燥.我可以将其分解为一个方法并将其混合到ActiveRecord中,但在我走这条路之前,我想知道是否有办法做到这一点.

Sim*_*tti 50

是的,目前唯一的选择是使用回调.

before_save :normalize_blank_values

def normalize_blank_values
  attributes.each do |column, value|
    self[column].present? || self[column] = nil
  end
end
Run Code Online (Sandbox Code Playgroud)

您可以将代码转换为mixin,以便将其轻松地包含在多个模型中.

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
Run Code Online (Sandbox Code Playgroud)

或者您可以在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
Run Code Online (Sandbox Code Playgroud)

  • @SimoneCarletti但有一件事......`false.present?== false`,`false.to_s.present?== true`.对于模型字段很重要,默认情况下应该是布尔值(例如false) (2认同)
  • 另外,不是写`self[column].present?|| self[column] = nil` 你可以像这样使用 `.presence` 方法:`self[column] = self[column].presence` (2认同)

dex*_*ter 19

尝试这个宝石是否有效:

https://github.com/rubiety/nilify_blanks

提供了一个框架,用于在数据库中将传入的空值保存为nil,而不是简单地使用空字符串...

在Rails中,当从表单保存模型并且用户不提供值时,会将空字符串记录到数据库而不是许多人希望的NULL(混合空白和NULL会变得混乱).此插件允许您指定属性列表(或所有属性中的异常),如果在保存模型之前它们为空,则将转换为nil.

只有属性响应空白?值为true的值将转换为nil.因此,这不适用于值为0的整数字段,例如......

  • 我最终使用了[attribute_normalizer](https://github.com/mdeering/attribute_normalizer),它可以实现nilification和更多功能,例如剥离空白,开箱即用. (7认同)

tro*_*skn 8

另一个选择是提供自定义setter,而不是在钩子中处理它.例如:

def foo=(val)
  super(val == "" ? nil : val)
end
Run Code Online (Sandbox Code Playgroud)


ser*_*hei 5

我的建议:

# 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
Run Code Online (Sandbox Code Playgroud)