Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the arel table of a habtm association?

I have two ActiveRecord models which have a HABTM association.

I want to write a scope to get the orphan records using Arel.

My problem is that I couldn't find a method to retrieve the arel_table of the association. Since the relation is HABTM, there is no model to call arel_table on.

I have the following now (which works), but I make a new arel table with the name of the join table (retrieved by using the reflect_on_association method).

scope :orphans, lambda {
    teachers = arel_table
    join_table = Arel::Table.new(reflect_on_association(:groups).options[:join_table])

    join_table_condition = join_table.project(join_table[:teacher_id])
    where(teachers[:id].not_in(join_table_condition))
}

This produces the following SQL:

SELECT `teachers`.* 
FROM `teachers`    
WHERE (`teachers`.`id` NOT IN (SELECT `groups_teachers`.`teacher_id`  
                               FROM `groups_teachers` ))

So is there any better way to retrieve the arel_table instead of making a new one?

like image 560
Maher4Ever Avatar asked Jan 05 '12 17:01

Maher4Ever


2 Answers

Unfortunately, I believe your solution is pretty much the cleanest there is right now and is, in fact, what the association itself does internally when instantiated:

https://github.com/rails/rails/blob/46492949b8c09f99db78b9f7a02d039e7bc6a702/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb#L7

I believe the reflection.join_table they use vs reflection.options[:join_table] is only in master right now though.

like image 117
Mike Auclair Avatar answered Nov 08 '22 23:11

Mike Auclair


If you know the name of the association and therefore the join table, which in this case it looks like you do, you should be able to call:

Arel::Table.new(:groups_teachers)

In my testing that returns Arel table of a habtm association. Thanks to this answer for pointing this out to me.

like image 2
Andrew Avatar answered Nov 08 '22 23:11

Andrew