【问题标题】:How to iterate ActiveRecord Attributes, including attr_accessor methods如何迭代 ActiveRecord 属性,包括 attr_accessor 方法
【发布时间】:2010-11-02 21:23:07
【问题描述】:

我到处寻找优雅的解决方案。根本问题似乎是映射到数据库列的 ActiveRecord 属性在 ActiveRecord::Base 中的处理方式与 attr_accessor 方法完全不同。

我想做这样的事情:

model.attribute_names.each do |name|
  # do stuff
end

以某种方式也包括 attr_accessor 字段,但不包括任何其他实例方法。我知道这不是内置的,但最优雅的方法是什么?

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:

    你无法真正解决这个问题。你可以近似一个 hack,但它永远不会很好地工作。

    model.attribute_names 应该为您提供所有 ActiveRecord 的,但 attr_accessor 字段不是字段。它们只是普通的 ruby​​ 方法,获取它们的唯一方法是使用model.instance_methods

    想法 1

    您可以使用model.attribute_names + model.instance_methods,但是您必须过滤掉所有其他正常的 ruby​​ 方法 initialize, save 等,这是不切实际的。

    为了帮助过滤instance_methods,您可以将它们与model.instance_variables 匹配(您必须手动考虑@ 登录实例变量),但这样做的问题是实例变量不t 实际上存在,直到它们被第一次分配。

    想法 2

    在您的environment.rb 中,在加载其他任何东西之前,在ActiveRecord::Base 中定义您自己的self.attr_accessor。然后,这可以包装底层的attr_accessor,但也可以将属性名称保存到私有列表中。然后,您以后就可以退出此列表。但是我建议不要这样做......像attr_accessor 这样的猴子补丁核心语言设施肯定会给你带来很多痛苦。

    想法 3

    ActiveRecord::Base 中定义您自己的custom_attr_accessor,它的作用与想法2 相同,并在您希望能够检索属性名称的代码中使用它。这将是安全的,因为您不会再破坏内置的 attr_accessor 方法,但您必须更改所有代码以在必要时使用 custom_attr_accessor

    我想总而言之,您想做什么需要了解所有 attr_accessor 字段?如果可以,请尝试从不同的角度看待您的问题。

    【讨论】:

    • +1 谢谢。我正在做一些处理表单字段的事情。无论如何,我完全同意从不同的角度看待事物!由于尚未在 SO 上提出/回答此问题,因此我认为这是一个很好的问题。
    • 是否有获取属性类/列类型以生成表单字段。如果属性没有值,它总是 nil。
    • 您也可以将 false 传递给 instance_methods 方法并排除继承的方法,进一步缩小范围:model.instance_methods(false)
    【解决方案2】:

    我来这里是为了做同样的事情,但由于 Orion 的回答,我发现这是完全错误的方法。

    如果其他人的用例与我的相似,这是我的解决方案。在从 ActiveRecord 查询模型后,我使用 attr_accessor 向模型添加额外的属性。然后我想将结果输出为 JSON 等。

    更好的解决方案是首先将 ActiveRecord 中的模型转换为常规哈希,然后添加 attr_accessor 属性作为常规哈希键。

    例子:

    model_hash = model_from_activerecord.attributes.to_options
    model_hash[:key] = value
    

    【讨论】:

      【解决方案3】:

      我自己提出的解决方案是基于 Orion Edwards 的回答。

      代码:

      klass_attributes = klass.column_names + klass.instance_methods(false). map(&:to_s).keep_if{|a| a.include?('=')}.map{|a| a.sub('=', '')}

      细分:

      klass.instance_methods(false) 只带回实例方法,不带回继承方法。

      map(&:to_s) 将符号数组转换为字符串数组,因此我们可以使用include? 方法。还需要与 column_names 返回的字符串数组合并。

      keep_if{|a| a.include?('=')} 将删除数组中没有等号的所有字符串。这很重要,因为我注意到 attr_accessor 属性都有'='。例如:“app_url”与“login_url=”

      map{|a| a.sub('=', '')} 是最后一块,然后从数组中的每个字符串中删除“=”。

      您最终会得到一个表示属性的字符串数组,包括 attr_accessor 属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-20
        • 1970-01-01
        • 2010-09-27
        • 1970-01-01
        • 1970-01-01
        • 2016-07-05
        相关资源
        最近更新 更多