如何迭代ActiveRecord属性,包括attr_accessor方法
我到处寻找一个优雅的解决方案。 基本问题似乎是,在ActiveRecord :: Base中,映射到数据库列的ActiveRecord属性与attr_accessor方法完全不同。
我想做的事情如下:
model.attribute_names.each do |name| # do stuff end
以包含attr_accessor字段的方式,但不包括任何其他实例方法。 我知道这不是内置的,但最优雅的方法是什么?
你无法解决这个问题。 你可以近似一个黑客,但它不是一个可以很好地工作的东西。
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
匹配(你必须手动考虑实例变量中的@
符号),但问题是实例变量实际上根本不存在,直到它们首先被分配。
想法2
在您的environment.rb
,在加载任何其他内容之前,在ActiveRecord::Base
定义您自己的self.attr_accessor
。 然后,这可以包装底层的attr_accessor
但也将属性名称保存到私有列表。 然后你就可以在以后退出这个列表了。 但是我建议不attr_accessor
……像attr_accessor
这样的猴子修补核心语言设施attr_accessor
会给你带来很大的痛苦。
想法3
在ActiveRecord::Base
定义自己的custom_attr_accessor
,它与Idea 2完全相同,并在您希望能够检索属性名称的代码中使用它。 这将是安全的,因为你不会再破坏内置的attr_accessor
方法,但你必须更改所有代码以使用必要的custom_attr_accessor
attr_accessor
,你想要做什么,需要了解所有的attr_accessor
字段? 如果可以的话,尝试从不同的角度看问题。
我来到这里寻找同样的事情,并且由于猎户座的回答,我发现这是完全错误的做法。
如果其他人的用例与我的相似,这是我的解决方案。 在使用ActiveRecord查询模型后,我正在使用attr_accessor
为模型添加额外的属性。 然后我想将结果输出为JSON等。
更好的解决方案是首先将模型从ActiveRecord转换为常规哈希,然后将attr_accessor
属性添加为常规哈希键。
例:
model_hash = model_from_activerecord.attributes.to_options model_hash[:key] = value
我为自己想出的解决方案建立在猎户座爱德华兹的回答之上。
代码:
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)
仅返回实例方法,而不返回inheritance的方法。
map(&:to_s)
将符号数组转换为字符串数组,以便我们可以使用include?
方法。 还需要与column_names返回的字符串数组合并。
keep_if{|a| a.include?('=')}
keep_if{|a| a.include?('=')}
将删除数组中没有等号的所有字符串。 这很重要,因为我注意到attr_accessor属性都有’=’。 例如:’app_url’vs’login_url =’
map{|a| a.sub('=', '')}
map{|a| a.sub('=', '')}
是最后一个部分,然后从数组中的每个字符串中删除’=’。
最终得到一个表示属性的字符串数组,包括attr_accessor属性。