0

我有一个 Rails 5 类,其中包括 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(...)定义得更远,它起作用并且它的返回值是正确的)。我发现设置此变量的唯一方法是改为编写self.productontology。此外,实例变量@uri没有定义为属性,而是仅在此位置记录并从外部可见。

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

我也对任何指向文档的指针感到满意。我无法找到 ActiveAttr 的文档,显示在 ActiveAttr 类的方法中对实例变量的操作。

谢谢 :-)

4

1 回答 1

0

首先,您很可能不需要 ActiveAttr gem,因为它实际上只是复制了 Rails 5 中已经可用的API 。

请参阅https://api.rubyonrails.org/classes/ActiveModel.html

正如我所写的,方法 fetch_po_field 不起作用,它认为 productontology 是一个局部变量。

这实际上只是 Ruby 的事情,与 Rails Attributes API 或 ActiveAttr gem 无关。

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

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

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

谁能解释为什么我需要编写 self.productontology,使用 @productontology 不起作用

考虑这个简单的旧红宝石示例:

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 实例方法以及一些关于属性的元数据,例如存储在类中的“类型”、默认值等。

于 2021-01-15T02:09:06.703 回答