rails text_field / text_ara空字符串vs nil

时间:2016-05-13 12:04:24

标签: ruby-on-rails database null null-object-pattern

我甚至不确定我是否有问题,但我不喜欢我的text_fields和text_areas以[{1}}而不是empty string的形式保存在数据库中。

我正在使用空对象模式,只是意识到我是否创建了个人资料但是没有填写位置字段,然后拨打nil然后它就不会爆炸因为位置是一个字符串,即使它是空的。

这是轨道惯例吗?如果是这样,为什么呢?这有点奇怪,因为我们说配置文件中有一个<%= @user.profile.location.upcase %> attr,然后我尝试调用类似

的内容
number_of_pets
因为我无法拨打<% if user.profile.number_of_pets.odd? %> <%= @user.profile.first_name %> has odd number of pets <% end %> ,所以它会被打破。

像往常一样

形成,如果没有填充,它将保存为空字符串

nil.odd?

2 个答案:

答案 0 :(得分:3)

最简单的解决方法是使用像“strip_attributes”这样的宝石:https://github.com/rmm5t/strip_attributes

可以通过在模型中添加before_save回调来完成自定义解决方法,该回调采用任何空白值并将其设置为nil。

在您的模型中,例如:

before_save :my_nil_maker_method_lol

[...]

def my_nil_maker_method_lol
  if self.whatever_attribute.blank?
    self.whatever_attribute=nil
  end
end

<强>更新

保存空白字段可以通过上述几种方式完成,甚至可以在控制器中删除空白参数之前将其删除。

在维护数据库完整性时,Rails方法始终将此逻辑保留在模型中。这使得维护变得更加容易,并且为您的其他地方修改传入参数提供了更少的惊喜空间。

至于在模型中应该如何完成,实际上只是开发人员希望获得输入的内容。您可以添加如上所示的回调,根据您的需要维护您的数据库,或者您可以添加validates_presence_of验证,如果该字段留空,将向用户返回错误。

如果你问是否应该保持空字符串不被插入到数据库中,那么由于可能存在你可能想要这些信息但在这种情况下它听起来的情况,这真的取决于你好像你想要限制空字符串。

答案 1 :(得分:1)

我是根据我观察到的,并不一定是Rails惯例。

例如,当我们执行rails g post title content:text时,您可能会记住它对于标题(字符串)和内容(文本)都没有default: ''。这已经暗示我没有关于此的Rails约定,或者具体来说默认情况下每个属性都允许为NULL或nil。

使用NULL的优点是您可以识别哪些记录设置了这些属性。

我们说我们有一台API服务器。如果客户端向我们的API服务器创建帖子,我们就知道哪些属性具有值。让我们说出如下内容:

客户1的POST参数:

post: {title: 'Foo bar'}
  • 如果允许NULL,则会创建Post(title: 'Foo bar', content: nil)
  • 如果默认:&#39;&#39;,则会创建Post(title: 'Foo bar', content: '')

客户-2的POST参数:

post: {title: 'Foo bar', content: ''}
  • 如果允许NULL,则会创建Post(title: 'Foo bar', content: '')
  • 如果默认:&#39;&#39;,则会创建Post(title: 'Foo bar', content: '')

从上面看,如果我们有默认值:&#39;&#39;,那么我们无法知道客户端是否实际上打算有一个空content值,因为对于client-1和客户端2,帖子的结果content值将为&#39;&#39; (空)无论如何。但是如果我们有NULL允许的属性,那么我们仍然可以通过不传入参数中的属性来识别客户端是否打算不具有content值。这是一个重要的用例。

根据您的项目和属性的用途,您可以使用NULL-allowed或为该属性设置默认空字符串。

现在,您遇到的NULL允许的一个主要问题是您不能保证每个值都是String,因此<%= @user.profile.location.upcase %>会在location引发错误是NULL或nil。

这可能有点烦人,特别是如果你有像你的例子那样的方法链

<%= @user.profile.location.upcase.downcase %>

如果@user.profile.location为零,这将是一个问题,因为您必须优雅地确保它不会引发错误。如果@user.profile为零,这也是一个问题(让我们假设您允许@user.profile为零)。通常情况下,您可以执行以下操作来完成这项工作:

<% if !@user.profile.nil? && !@user.profile.location.nil? %> 
  <%= @user.profile.location.upcase.downcase %>
<% end %>

if条件仍然可以持续很长时间,因为你有更长的链接方法来优雅地确保它不会引发任何错误。

使用.try()可能会&#34;清理&#34;这个。我经常使用它很多次,特别是在模板文件中。如下所示,解决方案将更加清晰,尽管可能会让那些不知道的人感到困惑:

 <%= @user.profile.try(:location).try(:upcase).try(:downcase) %>

如果.location.upcase为零,则返回nil,不再提出任何undefined method ... for NilClass