James
James

Reputation: 69

Is there a better way to find children and parents of an ActiveRecord object?

I'm working on a gem to export a small portion of related ActiveRecord objects.

Here's how I'm currently finding parents & children.

# belongs_to, based on column names with an _id suffix
def belongs_to_relations(ar_instance)
    columns = ar_instance.class.column_names
    parents = columns.map{ |c| c if c =~ /_id/ }.reject{ |c| c.nil? }
    parents.map!{ |parents| parents.gsub('_id', '') }
end

# has_many, based on existence of a xxx_id column in other tables
def has_many_relations(ar_instance)
    column_name = "#{ar_instance.class.name.underscore}_id"
    descendents = ActiveRecord::Base.connection.tables
    descendents.reject!{ |table| false unless table.classify.constantize rescue true }
    descendents.reject!{ |table| true unless table.classify.constantize.column_names.include?(column_name) }
end

Is there a better way to find these relationships? This works ok, but distant relationships, like :through, I have to specify manually.

Upvotes: 0

Views: 49

Answers (2)

MrDanA
MrDanA

Reputation: 11647

Use class.reflections. It returns information about a model's relationships.

Imagine you have this simple set up:

# user.rb
belongs_to :user_type
has_many :user_logs

If you call User.reflections you will get a hash similar to the following:

{
  :user_type => <Reflection @macro=:belongs_to, etc. ...>,
  :user_logs => <Reflection @macro=:has_many, etc. ...>
}

The reflection is an instance of ActiveRecord::Reflection::AssociationReflection or ActiveRecord::Reflection::ThroughReflection. It contains information about which model it references, what the options are (like dependent => :destroy), what type of association it is (the @macro in my example), etc.

Upvotes: 1

Graham Slick
Graham Slick

Reputation: 6870

I'm not exactly sure if that's what you're looking for but ActiveRecord has helpers to do this. In your models:

#school.rb
has_many :classrooms

#classroom.rb
belongs_to :school

You can now use pretty much anywhere:

school = random_classroom.school
classrooms = school.classrooms

For a has_many :through relationship:

# school.rb
  has_many :students,
           :through => :classrooms

Upvotes: 0

Related Questions