How to create a rails habtm that deletes/destroys without error?
I created a simple example as a sanity check and still can not seem to destroy an item on either side of a has_and_belongs_to_many relationship in rails.
Whenever I try to delete an object from either table, I get the dreaded NameError / "uninitialized constant" error message.
To demonstrate, I created a sample rails app with a Boy class and Dog class. I used the basic scaffold for each and created a linking table called boys_dogs. I then added a simple before_save routine to create a new 'dog' any time a boy was created and establish a relationship, just to get things setup easily.
dog.rb
class Dog < ActiveRecord::Base
has_and_belongs_to_many :Boys
end
boy.rb
class Boy < ActiveRecord::Base
has_and_belongs_to_many :Dogs
def before_save
self.Dogs.build( :name => "Rover" )
end
end
schema.rb
ActiveRecord::Schema.define(:version => 20100118034401) do
create_table "boys", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "boys_dogs", :id => false, :force => true do |t|
t.integer "boy_id"
t.integer "dog_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "dogs", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
end
I've seen lots of posts here and elsewhere about similar problems, but the solutions are normally using belongs_to and the plural/singular class names being confused. I don't think that is the case here, but I tried switching the habtm statement to use the singular name just to see if it helped (with no luck). I seem to be missing something simple here.
The actual error message is:
NameError in BoysController#destroy
uninitialized constant Boy::Dogs
The trace looks like:
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:105:开发者_C百科in
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/callbacks.rb:337:inconst_missing' (eval):3:in
destroy_without_callbacks'destroy_without_transactions' /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:229:in
send' ...
Thanks.
I don't see your destroy callback, but I do see a couple of problems. First, your associations need to be lowercase. So dog.rb should be:
class Dog < ActiveRecord::Base
has_and_belongs_to_many :boys
end
and boy.rb should be:
class Boy < ActiveRecord::Base
has_and_belongs_to_many :dogs
def before_save
self.dogs.build( :name => "Rover" )
end
end
Second, I believe you want to use self.dogs.create
instead of self.dogs.build
above, since build won't actually save the new dog object.
The accepted answer here solved my problem, only to create another one.
Here are my model objects:
class Complex < ActiveRecord::Base
set_table_name "Complexes"
set_primary_key "ComplexID"
has_and_belongs_to_many :amenities
end
class Amenity < ActiveRecord::Base
set_table_name "Amenities"
set_primary_key "AmenityID"
end
Rails uses the name of the association as the table name when creating the select query. My application runs on Unix against a legacy MySQL database and my table names are case-sensitive and don't conform to Rails conventions. Whenever my app actually tried to load the association, I would get an exception that MySQL couldn't find table amenities
:
SELECT * FROM `amenities`
INNER JOIN `ComplexAmenities` ON `amenities`.AmenityID = `ComplexAmenities`.AmenityID
WHERE (`ComplexAmenities`.ComplexID = 147 )
I searched and searched and could not find a way to tell Rails to use the correct case for the table name. Out of desperation, I tried passing a :table_name
option to habtm and it worked. My new Complex model looks like this:
class Complex < ActiveRecord::Base
set_table_name "Complexes"
set_primary_key "ComplexID"
has_and_belongs_to_many :amenities, :table_name => 'Amenities'
end
This works under Rails 2.3.5.
This option is not mentioned in the Ruby on Rails docs.
精彩评论