Rails ActiveAttr Gem,在 Class 内操纵属性?

Rails ActiveAttr Gem, manipulation of attributes within Class?

我有一个 Rails 5 class,其中包括 ActiveAttr::Model、ActiveAttr:MassAssignment 和 ActiveAttr::AttributeDefaults。

它使用方法 attribute 定义了几个属性,并且有一些实例方法。我在操作定义的属性时遇到了一些麻烦。我的问题是如何在初始化程序中设置属性值。部分代码:

class CompanyPresenter
  include ActiveAttr::Model
  include ActiveAttr::MassAssignment
  include ActiveAttr::AttributeDefaults

  attribute :identifier
  # ...
  attribute :street_address
  attribute :postal_code
  attribute :city
  attribute :country
  # ...
  attribute :logo
  attribute :schema_org_identifier
  attribute :productontology
  attribute :website

def initialize(attributes = nil, options = {})
    super
    fetch_po_field
  end

  def fetch_po_field
    productontology = g_i_f_n('ontology') if identifier
  end

  def uri
    @uri ||= URI.parse(website)
  end
  # ...
end

正如我所写的那样,fetch_po_field 方法不起作用,它认为 productontology 是一个局部变量(g_i_f_n(...) 被定义得更远,它起作用并且它的 return值正确)。我发现设置此变量的唯一方法是改写 self.productontology 。而且,实例变量@uri没有定义为属性,而是只写在这个地方,对外可见。

可能我只是忘记了 Ruby 和 Rails 的基础知识,我已经用 ActiveRecord 和 ActiveModel 做了这么长时间。任何人都可以解释为什么我需要写 self.productontology,使用 @productontology 不起作用,以及为什么我写原始代码的前辈将 @uri 中的 @ 符号与属性声明样式混合在一起?我想他一定是有什么理由这样做的。

我也对任何指向文档的指示感到满意。我一直无法找到 ActiveAttr 的文档,其中显示了在 ActiveAttr class.

方法中对实例变量的操作

谢谢:-)

首先,您很可能不需要 ActiveAttr gem,因为它实际上只是复制已经 available in Rails 5.

的 API

参见https://api.rubyonrails.org/classes/ActiveModel.html

As I have written it, the method fetch_po_field does not work, it thinks that productontology is a local variable.

这实际上只是一个 Ruby 问题,与 Rails 属性 API 或 ActiveAttr gem.

无关

使用赋值时,您必须显式设置接收者,除非您想设置局部变量。这一行:

self.productontology = g_i_f_n('ontology') if identifier

实际上是在 self 上使用 rval 作为参数调用 setter 方法 productontology=

Can anybody explain why I need to write self.productontology, using @productontology doesn't work

考虑这个普通的旧 ruby 示例:

class Thing
  def initialize(**attrs)
    @storage = attrs
  end

  def foo
    @storage[:foo]
  end

  def foo=(value)
    @storage[:foo] = value
  end
end
irb(main):020:0> Thing.new(foo: "bar").foo
=> "bar"
irb(main):021:0> Thing.new(foo: "bar").instance_variable_get("@foo")
=> nil

这看起来与您使用 attr_accessor 创建的标准访问器有很大不同。我们没有将“属性”存储在每个属性的一个实例变量中,而是使用哈希作为内部存储并创建访问器来公开存储的值。

Rails 属性 API 做完全相同的事情,除了它不仅仅是一个简单的散列,而且访问器是用元编程定义的。为什么?因为 Ruby 不允许您跟踪对简单实例变量的更改。如果您设置 @foo = "bar",则模型无法跟踪属性的更改或执行类型转换之类的操作。

当你使用 attribute :identifier 时,你正在编写 setter 和 getter 实例方法以及一些关于属性的元数据,如它的“类型”、默认值等。存储在 class.