键入强制转换ActiveRecord模型虚拟属性

Hap*_*off 15 activerecord ruby-on-rails

我有一个带有一些属性和虚拟属性的模型.此虚拟属性用于在创建表单中创建一个复选框.

class Thing < ActiveRecord::Base
  attr_accessor :foo
  attr_accessible :foo
end
Run Code Online (Sandbox Code Playgroud)

由于该字段是表单中的复选框,因此该foo属性将接收'0''1'作为值.我希望它是一个布尔值,因为以下代码:

class Thing < ActiveRecord::Base
  attr_accessor :foo
  attr_accessible :foo

  before_validation :set_default_bar

  private

  def set_default_bar
    self.bar = 'Hello' if foo
  end
end
Run Code Online (Sandbox Code Playgroud)

这里的问题是条件即使在时foo也是如此'0'.我想使用ActiveRecord类型的转换机制,但我发现只有以下内容:

class Thing < ActiveRecord::Base
  attr_reader :foo
  attr_accessible :foo

  before_validation :set_default_bar

  def foo=(value)
    @foo = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
  end


  private

  def set_default_bar
    self.bar = 'Hello' if foo
  end
end
Run Code Online (Sandbox Code Playgroud)

但我觉得这样做很脏.没有重写转换方法,有没有更好的选择?

谢谢

Tyl*_*ick 15

原始帖子的解决方案对我来说是最好的解决方案.

class Thing < ActiveRecord::Base
  attr_reader :foo
  def foo=(value)
    @foo = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
  end
end
Run Code Online (Sandbox Code Playgroud)

如果你想稍微清理一下,你总是可以创建一个帮助器方法,foo=为你定义你的编写器方法value_to_boolean.

我可能会创建一个带有调用方法的模块,bool_attr_accessor因此您可以将模型简化为如下所示:

class Thing < ActiveRecord::Base
  bool_attr_accessor :foo
end
Run Code Online (Sandbox Code Playgroud)

似乎ActiveModel应该为我们提供这样的东西,因此虚拟属性更像是"真实"(ActiveRecord-persisted)属性.只要您具有从表单提交的布尔虚拟属性,此类型转换就非常重要.

也许我们应该向Rails提交补丁......


bob*_*lin 7

在 Rails 5 中,您可以使用attribute方法。此方法在此模型上定义具有类型的属性。如果需要,它将覆盖现有属性的类型。

class Thing < ActiveRecord::Base
  attribute :foo, :boolean
end
Run Code Online (Sandbox Code Playgroud)

注意:attribute在从数据库加载的模型上,rails 5.0.0中此功能的行为不正确。因此使用 rails 5.0.1 或更高版本。