Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails / ActiveRecord: detect if a column is an association or not

Assuming I am abstracting code, and am looping through the column names of object x, what's the best way to detect if a column is an association or not?

I know I can do this, but I am wondering if there is a better way:

@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

Any built-in Rails methods or helpers to detect associations? Code above is neither pretty nor fool proof. Thanks!

like image 449
David Lesches Avatar asked Nov 13 '12 04:11

David Lesches


People also ask

What is the difference between Has_one and Belongs_to?

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.

What does Active Record base do?

ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending. Edit: as Mike points out, in this case ActiveRecord is a module...

What is Active Record association in Rails?

Association in Rails defines the relationship between models. It is also the connection between two Active Record models. To figure out the relationship between models, we have to determine the types of relationship. Whether it; belongs_to, has_many, has_one, has_one:through, has_and_belongs_to_many.


1 Answers

One way to do this would be to reflect upon all associations for that class:

associations = class_goes_here.reflect_on_all_associations

And then to find just the belongs_to ones, since those will have the _id field:

associations = associations.select { |a| a.macro == :belongs_to }

Then you can find the foreign key used on these associations by doing this:

association_foreign_keys = associations.map(&:foreign_key)

I wouldn't use @user.attributes to get the attributes and then keys on that to get the column names. I would use User.column_names to get the column names.

Therefore, with all that explained, you can then change your code to be this to make it more foolproof:

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
like image 113
Ryan Bigg Avatar answered Nov 09 '22 02:11

Ryan Bigg