如何在 Rails Ruby 中为模型添加虚拟属性?

How to add a virtual attribute to a model in Ruby on Rails?

我正在开发 RubyonRails/ActiveAdmin 应用程序。我的RoR版本是4.2.5,AA版本是1.0.0。我有一个模型 Message 如下。

class Message < ActiveRecord::Base

  belongs_to :user
  validates :user, :content, presence: true

  def palindrome
    # return true/false
  end

end

如您所见,我想要一个只读属性palindrome,它只依赖于消息的content。我希望将此属性完全视为普通属性。通常,我的意思是当我通过 rails console 检索消息或请求 json 格式的消息时,我希望在列表中看到 palindrome 属性。我还想通过此属性过滤消息。

我不确定我怎样才能做到这一点。

在您的模型中,您可以通过这种方式为虚拟属性 palindrome 属性编写属性访问器 (reader/writer):

# attr_reader
def palindrome
  self[:palindrome]
end

# attr_writer
def palindrome=(val)
  self[:palindrome] = val
end

# virtual attribute
def palindrome
  #return true/false
end

并且,当您使用 Rails 4 时,您必须像控制器内的强参数定义中的任何其他模型属性一样将 palindrome 属性列入白名单,以便能够批量分配值palindrome 个。像这样:

# your_controller.rb
private

def your_model_params
  params.require(:message).permit(:palindrome)
end

看看这个RailsCast on Virtual Attributes。虽然有点旧,但对概念很有用。

注:

虚拟属性不会自动显示在参数列表中。但是,您应该能够像这样通过 Rails 控制台访问它:Message.new.palindrome。此外,您可以在 JSON API 中公开此虚拟属性,例如,如果您使用 Active Model Serializer,您可以在 MessageSerializer 中包含:attribute palindrome 和然后 palindrome 将暴露给 JSON API.

Ruby 实际上允许您以这种方式创建虚拟属性,这使您不必手动创建 getter 和 setter 方法:

attr_reader   :palindrome #getter
attr_writer   :palindrome #setter
attr_accessor :palindrome #both

您也可以传递多个参数:

attr_accessor :palindrome, :foo, :bar

documentation for it 不是最好的。

从Rails 5开始你也可以像这样设置虚拟属性:

attribute :palindrome, :boolean

它会自动将属性转换为指定的类型,这在值来自表单时很有用。 This GoRails video shows some really good examples of both using the attr_accessor and the attribute approach. The documentation 还包括一些示例。