Habtm confusion


#1

Hello friends!

I am trying to make a database that will have a group of people set to
committees, and a person can be in multiple committees, and a committee
obviously has multiple people. The people are senators at my
university. These are my current models:

senator.rb:

class Senator < ActiveRecord::Base
validates_presence_of :first_name, :last_name, :floor
has_and_belongs_to_many :committees#, :dependent => :nullify
#has_many :chairs, :class_name => “Committee”#, :dependent => :nullify
end

The last has_many is commented out so that I can at least get this
working, and then I’ll add that in later. Also note that the :dependent
has been commented out. Is this deprecated or no longer supported?
What’s the deal?

committee.rb

class Committee < ActiveRecord::Base
validates_presence_of :name
has_and_belongs_to_many :senators #, :dependent => :nullify
#has_one :head, :class_name => “Senator” #, :dependent => :nullify
end

Same as before on the comments.

Also, for my view I am trying the following:

Committee
<%= select(:senator, :committees, Committee.find(:all).map {|c| [c.name, c.id]}, {:include_blank => true}, {:multiple => true}) %>

--

On the view I get the following error:

ActiveRecord::StatementInvalid

and the trace:

/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/sqlite_adapter.rb:360:in
table_structure' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/object/misc.rb:23:inreturning’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/sqlite_adapter.rb:359:in
table_structure' /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/sqlite_adapter.rb:210:incolumns’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/associations/has_and_belongs_to_many_association.rb:165:in
finding_with_ambigious_select?' /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/associations/has_and_belongs_to_many_association.rb:55:infind’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/associations/association_collection.rb:159:in
find_target' /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/associations/association_proxy.rb:131:inload_target’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/associations/association_proxy.rb:29:in
respond_to?' /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_options_helper.rb:116:inoptions_for_select’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1358:in
inject' /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_options_helper.rb:114:ineach’
/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_options_helper.rb:114:in
inject' /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_options_helper.rb:114:inoptions_for_select’
/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_options_helper.rb:302:in
to_select_tag' /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_options_helper.rb:66:inselect’
#{RAILS_ROOT}/app/views/admin/_form.rhtml:26:in
_run_rhtml_47app47views47admin47_form46rhtml' #{RAILS_ROOT}/app/views/admin/edit.rhtml:4:in_run_rhtml_47app47views47admin47edit46rhtml’
#{RAILS_ROOT}/app/views/admin/edit.rhtml:3:in
`_run_rhtml_47app47views47admin47edit46rhtml’

Any help at all would be much appreciated.


#2

Frew S. schrieb:

validates_presence_of :first_name, :last_name, :floor
committee.rb
Also, for my view I am trying the following:
ActiveRecord::StatementInvalid
columns' /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/form_options_helper.rb:116:into_select_tag’

first, you have a “committees_senators” table to manage your many-many
join

second, your rhtml looks odd to me, I haven’t used that in a while but I
think the bit…

:senator, :committees,

… looks wrong

I’m guessing you want a list of committees. You should have something
more like…

Committee
> <%= select('committee', 'committee_id', > Committee.find(:all).map {|c| [c.name, c.id]}, > {:include_blank => true}, {:multiple => true}) %> >

… if you want the committees a senator is associated with you’ll need
to add some extra code, something like “:selected => [Arr of Committee
Id’s]” should work

finally, I think :dependent is for has_many, not habtm. You should
check the documentation to be certain. http://api.rubyonrails.org

good luck,

andy koch


#3

Thanks for the reply Andy!

first, you have a “committees_senators” table to manage your many-many
join

I know that, but that’s abstracted away right? I don’t need to deal
with it, do I?

Committee
> <%= select('committee', 'committee_id', > Committee.find(:all).map {|c| [c.name, c.id]}, > {:include_blank => true}, {:multiple => true}) %> >

as for the rhtml, the docs said the following:

select(object, method, choices, options = {}, html_options = {})

so I presumed that I wanted :senator, :committees, but now that I think
about that, that really doesn’t make a whole lot of sense.

… if you want the committees a senator is associated with you’ll need
to add some extra code, something like “:selected => [Arr of Committee
Id’s]” should work

Nah, I’ll do that later, once I have the basics figured out.

finally, I think :dependent is for has_many, not habtm. You should
check the documentation to be certain. http://api.rubyonrails.org

Yeah, I realized last night that :dependent really doesn’t make any
sense at all for habtm, because there is the intermediary table. I’m
sure I don’t need to explain it to you guys.

Thanks a bunch for the tips. When I get time I will make modifications
based on this and see how things go.

-fREW


#4

Frew S. schrieb:

Thanks for the reply Andy!

first, you have a “committees_senators” table to manage your many-many
join

I know that, but that’s abstracted away right? I don’t need to deal
with it, do I?

-fREW

correct, but you must first create the table in your DB with appropriate
structure

/ak


#5

Andy K. wrote:

Frew S. schrieb:

Thanks for the reply Andy!

first, you have a “committees_senators” table to manage your many-many
join

I know that, but that’s abstracted away right? I don’t need to deal
with it, do I?

-fREW

correct, but you must first create the table in your DB with appropriate
structure

Oooh!

I never made that connection. Here is the migration that I have made to
define the table. Tell me if anything looks totally wrong with it:

005_create_committees_senators.rb

class CreateCommitteesSenators < ActiveRecord::Migration
def self.up
create_table :committees_senators do |t|
t.column :committee_id, :integer
t.column :senator_id, :integer
end
end

def self.down
drop_table :committees
end
end

(It seems to have worked so far.)


#6

Frew S. schrieb:


end
end

(It seems to have worked so far.)

close, but you’re missing a few bits. See this rewrite…

def self.up
create_table :committees_senators, :id => false do |t|
t.column :committee_id, :integer, :null => false
t.column :senator_id, :integer, :null => false
end

say “Add unique index on ‘committees_senators’”, true
add_index(:committees_senators, [:committee_id, :senator_id], :unique =>
true)
end


The difference is:

  1. this removes the ‘id’ column from your join table with the “:id =>
    false”, it is not needed since the joined pairs are the key
  2. enforces in DB that neither ID in a pair may ever be null (:null =>
    false)
  3. creates a unique index on the table, while this isn’t a true primary
    key index it does ensure you won’t have any duplicity in the table.

And that should do it.

andy