我到处寻找优雅的解决方案。基本问题似乎是,在ActiveRecord :: Base中,映射到数据库列的ActiveRecord属性与attr_accessor方法完全不同。
我想做点什么:
model.attribute_names.each do |name|
# do stuff
end
的方式还包括attr_accessor字段,但不包括任何其他实例方法。我知道这不是内置的,但最优雅的方法是什么?
答案 0 :(得分:9)
你无法解决这个问题。你可以近似一个黑客攻击,但它不会很好地工作。
model.attribute_names
应该为您提供所有ActiveRecord,但attr_accessor
字段不是字段。它们只是普通的ruby方法,获取它们的唯一方法是使用model.instance_methods
。
你可以model.attribute_names + model.instance_methods
,但是你必须过滤掉所有其他正常的红宝石方法initialize, save
等,这是不切实际的。
要帮助过滤instance_methods
,您可以将它们与model.instance_variables
进行匹配(您必须手动考虑实例变量中的@
符号),但问题是是实例变量在首次分配之前根本不存在。
在environment.rb
中,在加载任何其他内容之前,请在self.attr_accessor
中定义您自己的ActiveRecord::Base
。然后,这可以包装基础attr_accessor
,但也将属性名称保存到私有列表。然后你就可以在以后退出这个列表了。但是我建议不要这样做......像attr_accessor
这样的猴子修补核心语言设施可以保证给你带来很大的痛苦。
在custom_attr_accessor
中定义您自己的ActiveRecord::Base
,其功能与Idea 2相同,并在您希望能够检索属性名称的代码中使用它。这样会很安全,因为您不会再破坏内置的attr_accessor
方法,但是您必须更改所有代码才能使用custom_attr_accessor
总的来说,您想要做什么,需要了解所有attr_accessor
字段?如果可以,请尝试从不同角度查看问题。
答案 1 :(得分:3)
我来到这里寻找做同样的事情,并且由于猎户座的回答,发现这是错误的做法。
包括其他人的用例与我的相似,这是我的解决方案。在使用ActiveRecord查询模型后,我使用attr_accessor
为模型添加了额外的属性。然后我想把结果输出为JSON等。
更好的解决方案是首先将模型从ActiveRecord转换为常规哈希,然后将attr_accessor
属性添加为常规哈希键。
示例:
model_hash = model_from_activerecord.attributes.to_options
model_hash[:key] = value
答案 2 :(得分:0)
我为自己提出的解决方案建立在猎户座爱德华兹的回答之上。
代码:
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'vs'login_url ='
map{|a| a.sub('=', '')}
是最后一段,然后从数组中的每个字符串中删除'='。
最终得到一个表示属性的字符串数组,包括attr_accessor属性。