4

我什至不确定我是否有问题,但我只是不喜欢我的 text_fields 和 text_areas 保存在数据库中empty string而不是nil.

我正在使用空对象模式并且刚刚意识到如果我创建了一个配置文件但不填写位置字段然后调用<%= @user.profile.location.upcase %>它不会爆炸,因为位置是一个字符串,即使它是空的。

这是 Rails 的惯例吗?如果是这样,那为什么?这有点奇怪,因为假设number_of_pets个人资料上有一个 attr 然后我尝试调用类似的东西

<% if user.profile.number_of_pets.odd? %>
  <%= @user.profile.first_name %> has odd number of pets
<% end %>

然后它爆炸了,因为我不能打电话nil.odd?

像往常一样表单,所以如果没有填写,它将保存为空字符串

<%= form_for @profile, url: user_profile_path do |f| %>
  <%= f.label :city %>
  <%= f.text_field :location, class: 'form-control' %>
  ......
4

2 回答 2

4

最简单的解决方法是使用此处的“strip_attributes”之类的 gem: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验证,如果该字段留空,该验证将向用户返回错误。

如果您要问是否应该完全避免将空字符串插入数据库,这完全取决于您作为开发人员,因为可能存在您可能需要该信息的情况,但在这种情况下,听起来好像您'正在寻找限制空字符串。

于 2016-05-13T12:13:46.763 回答
1

我说的是我观察到的,可能不一定是 Rails 约定。

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

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

假设我们有一个 API 服务器。如果客户端向我们的 API 服务器创建了一个帖子,我们就知道哪些属性应该具有值。让我们这样说:

client-1 的 POST 参数:

post: {title: 'Foo bar'}
  • 如果 NULL 允许,将创建一个Post(title: 'Foo bar', content: nil)
  • 如果默认:'',将创建一个Post(title: 'Foo bar', content: '')

client-2 的 POST 参数:

post: {title: 'Foo bar', content: ''}
  • 如果 NULL 允许,将创建一个Post(title: 'Foo bar', content: '')
  • 如果默认:'',将创建一个Post(title: 'Foo bar', content: '')

从上面,请注意,如果我们有默认值:'',那么我们无法知道客户端是否真的打算有一个空content值,因为对于客户端 1 和客户端 2,contentpost 的结果值将具有 '' (空)无论如何。content但是如果我们有 NULL 允许的属性,那么我们仍然可以通过不在参数中传递属性来识别客户端是否打算没有值。这是一个重要的用例。

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

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

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

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

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

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

if只要您有更长的链接方法来优雅地确保它不会引发任何错误,这种情况仍然可以持续很长时间。

使用.try()可能会“清理”它。我经常使用它,尤其是在模板文件中。解决方案将像下面这样更干净,尽管可能会让那些不知道的人感到困惑:

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

如果其中一个.location.upcase为 nil,它将返回 nil,并且不再加注undefined method ... for NilClass

于 2016-05-13T13:49:42.603 回答