10

假设我正在抽象代码,并且正在遍历对象 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 方法或帮助程序来检测关联?上面的代码既不漂亮也不傻。谢谢!

4

2 回答 2

19

一种方法是反思该类的所有关联:

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
于 2012-11-13T04:30:32.887 回答
1

我确信选定的解决方案会更好,但如果你生活在“理想世界”中,每个人都遵循 Rails 约定,我想你可以依靠这个

2.2模式约定 Active Record 对数据库表中的列使用命名约定,这取决于这些列的用途。

外键——这些字段应该按照模式singularized_table_name_id 命名(例如,item_id、order_id)。这些是 Active Record 在您创建模型之间的关联时将查找的字段。

因此,只需在列名末尾查找 _id 后缀:

Model.column_names.select{|cn| cn.include?("_id")}
于 2015-08-07T13:28:55.270 回答