假设我正在抽象代码,并且循环遍历对象x的列名,那么检测列是否为关联的最佳方法是什么?
我知道我可以做到这一点,但我想知道是否有更好的方法:
@user = User.first
@user.attributes.keys.each do |column|
if column[-3..-1] == "_id" && @user.respond_to?(column[0..-4].to_sym)
puts "#{column} is an association / relation."
else
puts "#{column} is not an assocation / relation."
end
end
end
任何内置的Rails方法或帮助程序来检测关联?上面的代码既不漂亮,也不是万无一失。谢谢!
答案 0 :(得分:17)
这样做的一种方法是反思该类的所有关联:
associations = class_goes_here.reflect_on_all_associations
然后只找到belongs_to
个,因为那些会有_id
字段:
associations = associations.select { |a| a.macro == :belongs_to }
然后,您可以通过执行以下操作找到在这些关联上使用的外键:
association_foreign_keys = associations.map(&:foreign_key)
我不会使用@user.attributes
来获取属性,然后使用keys
来获取列名称。我会使用User.column_names
来获取列名。
因此,通过所有解释,您可以将代码更改为此以使其更加万无一失:
associations = User.reflect_on_all_associations
associations = associations.select { |a| a.macro == :belongs_to }
association_foreign_keys = associations.map(&:foreign_key)
User.column_names.each do |column|
if association_foreign_keys.include?(column)
puts "#{column} is an association / relation."
else
puts "#{column} is not an assocation / relation."
end
end
答案 1 :(得分:1)
我确信选择的解决方案更好,但如果你生活在“理想世界”中,每个人都遵循铁轨惯例,我想你可以依靠this:
2.2 架构约定Active Record使用命名约定 数据库表中的列,具体取决于这些列的用途。
外键 - 这些字段应按照模式命名 singularized_table_name_id(例如,item_id,order_id)。这些是 创建关联时Active Record将查找的字段 在你的模特之间。
所以只需在列名末尾查找_id后缀:
Model.column_names.select{|cn| cn.include?("_id")}