Once I added this HABTM, one of my 'through' relationships, on a non-habtm model, seems to have broke?

I’m a rails newb and have been Googling about this, but I’m still stumped.

Not showing everything here, but basically it should be a pretty common setup so I’m sure others know what I’m doing wrong.

  • A meter can belong to many meter_groups
  • A meter_group can have many meters.
  • A user can ‘subscribe’ to viewing a meter_group (Subscription) so he should be able to see the meters that are in that meter_group of the subscription (think subscribing to a topic in a forum.)

Initially I was only allowing a single meter to belong to only one meter_group and the following test and relationship of a Subscription worked fine:

class Subscription < ActiveRecord::Base
belongs_to :user, :foreign_key => “user_id”

belongs_to :meter_group, :foreign_key => “meter_group_id”
has_many :meters, :through => :meter_group
end

test “group1 and group2 belong to rachel” do
user = User.find_by_login(“rachel”)

subscriptions = Subscription.find_all_by_user_id([user.id](http://user.id))
subscriptions.each do |s|
  meters = s.meters
  meters.each do |m|
    puts "meter = #{p m}"

  end
end

end

However now things are not working since I created some HABTM relationships for meter_group and meters. I end up with the following error:

ActiveRecord::HasManyThroughSourceAssociationMacroError: Invalid source reflection macro :has_and_belongs_to_many for has_many :meters, :through => :meter_group. Use :source to specify the source reflection.

Here are some of the other relevant tables and migrations (stripped of a few non-related fields):

class MeterGroup < ActiveRecord::Base
belongs_to :user, :foreign_key => “user_id”
has_and_belongs_to_many :meters

end

class Meter < ActiveRecord::Base
has_and_belongs_to_many :meter_groups
belongs_to :user, :foreign_key => “user_id”
end

#Migrations (removed some cols and drop section)

class CreateMeterGroups < ActiveRecord::Migration
def self.up
create_table :meter_groups do |t|
t.string :name
t.string :description
t.integer :user_id

  t.timestamps

end

end
end

class CreateMeters < ActiveRecord::Migration
def self.up
create_table :meters do |t|
t.integer :meter_type_id
t.integer :scale_id
t.integer :user_id

  t.string :name
  t.string :description

  t.timestamps
end

end
end

class CreateMetersMeterGroups < ActiveRecord::Migration
def self.up
create_table :meter_groups_meters, :id => false do |t|

  t.integer :meter_id
  t.integer :meter_group_id

  t.timestamps
end

end
end

class CreateSubscriptions < ActiveRecord::Migration
def self.up
create_table :subscriptions do |t|

  t.integer :user_id
  t.integer :meter_group_id
 
  t.timestamps
end

end
end

I’m a rails newb and have been Googling about this, but I’m still stumped.

Not showing everything here, but basically it should be a pretty common setup so I’m sure others know what I’m doing wrong.

  • A meter can belong to many meter_groups
  • A meter_group can have many meters.
  • A user can ‘subscribe’ to viewing a meter_group (Subscription) so he should be able to see the meters that are in that meter_group of the subscription (think subscribing to a topic in a forum.)

Initially I was only allowing a single meter to belong to only one meter_group and the following test and relationship of a Subscription worked fine:

class Subscription < ActiveRecord::Base
belongs_to :user, :foreign_key => “user_id”

belongs_to :meter_group, :foreign_key => “meter_group_id”
has_many :meters, :through => :meter_group
end

test “group1 and group2 belong to rachel” do
user = User.find_by_login(“rachel”)

subscriptions = Subscription.find_all_by_user_id([user.id](http://user.id))
subscriptions.each do |s|
  meters = s.meters
  meters.each do |m|
    puts "meter = #{p m}"



  end
end

end

As a side note, there isn’t an issue if I try to get meters directly from the meter_group. For example in the above test it works if changed to:
test “group1 and group2 belong to rachel” do
user = User.find_by_login(“rachel”)
subscriptions = Subscription.find_all_by_user_id(user.id)
subscriptions.each do |s|
meter_group = s.meter_group
meters = meter_group.meters

meters.each do |m|
puts “meter = #{p m}”
end
end
end

I would start by getting rid of the :foreign_key specifications
unless you are doing something non standard.

I would start by getting rid of the :foreign_key specifications

unless you are doing something non standard.

Ok, thanks. I removed them. (Didn’t fix the issue but does look a lot cleaner.)

oh you need to add the has_many for the join table

has_many :meter_goup
has_many :meters, :through => :meter_group

I take it you mean on the Subscription table? which currently looks like:

class Subscription < ActiveRecord::Base

belongs_to :user

belongs_to :meter_group

has_many :meters, :through => :meter_group

end

But a Subscription doesn’t have many mete groups, a subscription can only be tied to a single meterGroup and has a fk to the meter_group table.

Or are you saying for the other join table “meter_groups_meters” I need to make a MeterGroupsMeter model object and add the relationships you described?

For reference The other relevant tables are:

class Meter < ActiveRecord::Base
has_and_belongs_to_many :meter_groups
belongs_to :user
end

class MeterGroup < ActiveRecord::Base
belongs_to :user

has_and_belongs_to_many :meters
end

sorry I misread your tables. The has_many :through is looking for a
join table with ids for both sides which is the cause of the error,
same kind of table as a HABTM join table.

class Author < ActiveRecord::Base
    has_many :authorships
    has_many :books, :through => :authorships
  end

  class Authorship < ActiveRecord::Base
    belongs_to :author
    belongs_to :book
  end