Forum: Ruby on Rails Problem with .save when model has two HABTM

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4d5e28840f8628550a22c410cb73ad60?d=identicon&s=25 Mattias Bud (mattias)
on 2005-12-13 11:46
I have a problem with save on a model that contains two HABTM. When
create (save) only the categories are saved - the archives_medias table
stays untouched. On update both tables are updated.
This is how it looks now:

class Archive < ActiveRecord::Base
	has_and_belongs_to_many :categories
	has_and_belongs_to_many :medias
  	...

class ArchivesController < ApplicationController

    def create
    @archive = Archive.new(params[:archive])
    if request.post? && @archive.save
      flash[:notice] = 'Archive was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'edit'
    end

  def update
  @archive = Archive.find(params[:id])
    if request.post? && @archive.update_attributes(params[:archive])
      flash[:notice] = 'Archive was successfully updated.'
      redirect_to :action => 'list'
    else
      render :action => 'edit'
    end

The values of categries and medias are passed through checkboxes useing
the categories_ids and media_ids arrays.

I can't confirm it but I suspect this problem first accured after I
updated to 0.14.4. The model gets the data fine on both.

Strange?
0895305feb2b97049c39b08972233d02?d=identicon&s=25 Anthony Rudgick (Guest)
on 2005-12-13 11:52
I have encountered the exact same problem and have yet to find a
solution. hopefully someone can figure this quirky behavior out.

-A
C64e63b70be7dfed8b0742540b8b27e5?d=identicon&s=25 Mark Reginald James (Guest)
on 2005-12-13 12:40
(Received via mailing list)
Mattias Bodlund wrote:
> I have a problem with save on a model that contains two HABTM. When
> create (save) only the categories are saved - the archives_medias table
> stays untouched. On update both tables are updated.

Perhaps it's related to the pluralization and singularization of
"media".

--
We develop, watch us RoR, in numbers too big to ignore.
C64e63b70be7dfed8b0742540b8b27e5?d=identicon&s=25 Mark Reginald James (Guest)
on 2005-12-13 13:25
(Received via mailing list)
Anthony Rudgick wrote:
> I have encountered the exact same problem and have yet to find a
> solution. hopefully someone can figure this quirky behavior out.

Interesting.  I've also had problem with join table entries not
being added when the parent object is created.  I fixed it by
adding the related objects after saving the parent object,
but I was unable to reproduce the problem in some experiments
with a simple pair of related models.  So perhaps there is some
problem that only manifests in more complex code.  I'm using only
one HABTM, not two however.

--
We develop, watch us RoR, in numbers too big to ignore.
4d5e28840f8628550a22c410cb73ad60?d=identicon&s=25 Mattias Bud (mattias)
on 2005-12-13 14:52
Mark Reginald James wrote:
> Mattias Bodlund wrote:
>> I have a problem with save on a model that contains two HABTM. When
>> create (save) only the categories are saved - the archives_medias table
>> stays untouched. On update both tables are updated.
>
> Perhaps it's related to the pluralization and singularization of
> "media".
>
> --
> We develop, watch us RoR, in numbers too big to ignore.

I have tried to specify both:

:class_name => 'Media',
:join_table => 'archives_medias',

No difference.
4d5e28840f8628550a22c410cb73ad60?d=identicon&s=25 Mattias Bud (mattias)
on 2005-12-13 14:56
pluralize(2,'media')

-> 2 medias
413faf211358af7cae68c1f2137de0f8?d=identicon&s=25 Mel Riffe (Guest)
on 2005-12-13 15:59
(Received via mailing list)
Hi Everyone,

Oddly enough I was going to post something similar to this post.  Here's
my
situation and here's what a friend and I have found:

There is a model with 4 HABTM relationships.  When 'create' is executed
only
one HABTM is actually saved; the same one each time.  The remaining
three
would only be saved in 'update'.

Last night I found this in the ActiveRecord documents:  Adding an object
to
a collection
(has_many<http://ar.rubyonrails.com/classes/ActiveRecord/Ass...
has_and_belongs_to_many<http://ar.rubyonrails.com/classes/ActiveRecord/Ass...)
automatically saves that object, except if the parent object (the owner
of
the collection) is not yet stored in the database.

Not ideal, but like Mark Reginald James, we discovered saving the model
first then changing the associations and saving the model again produced
the
desired results.

So I went from 'Why aren't the other HABTMs saving?' to 'Why is that one
HABTM saving?'

Has anyone else experienced this situation?

Mel
4d5e28840f8628550a22c410cb73ad60?d=identicon&s=25 Mattias Bud (mattias)
on 2005-12-13 16:16
Just to clearify - this is also the behavior I see. Have also got it
working by saving the object twice. This just feels wrong when the first
HABTM is saved on the first save.
7a966bb1534f0ea863bc9ffe65ae449f?d=identicon&s=25 Jamie Orchard-Hays (Guest)
on 2005-12-13 16:23
(Received via mailing list)
Just to add to Mel's comments (I'm working with him):

We could find no logical reason why one of our associations always
saved and the others never did on a creation of a new owner. For
example:

f = Foo.new
f.ass_1_ids = [1,2,3]
f.ass_2_ids = [1,2,3]
f.ass_3_ids = [1,2,3]

f.save

ass_1s always were persisted.
ass_2s and ass_3s never were.

I experimented with the issue in script/console for quite a while
last night, even switching dbs from Sqlite to MySql and even changing
our table column names to be totally rails conventional. Nothing
changed.

Interestingly, one of the associations that always failed on the web
app worked in the console.

Another datapoint is that the associations were fetched with now
problems when assigned to the owner (an excerpt from my console):

?> r = Recipe.new
=> #<Recipe:0x252c94c @attributes={"name"=>nil,
"experiment_type_id"=>nil, "replicate_type_id"=>nil,
"description"=>nil, "workorder_id"=>nil}, @new_record=true>
 >> r.name = 'kinase recipe'
=> "kinase recipe"
 >> r.description = 'description'
=> "description"

#### assign the kinases:

 >> r.kinase_ids=[1,2,3]
=> [1, 2, 3]
 >> r
=> #<Recipe:0x252c94c @attributes={"name"=>"kinase recipe",
"experiment_type_id"=>nil, "replicate_type_id"=>nil,
"description"=>"description", "workorder_id"=>nil}, @new_record=true,
@kinases=[#<Kinase:0x251fe2c @attributes=
{"ref_inhib_compound_id"=>"10", "name"=>"c-RAF(h)",
"active_f"=>"17807", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"10", "id"=>"1", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10", "description"=>"45.00000000",
"catalog_number"=>"c-RAF(h)", "km_conc"=>"47.00000000",
"ref_inhib_known_value"=>"14"}>, #<Kinase:0x251fdf0 @attributes=
{"ref_inhib_compound_id"=>"1", "name"=>"MEK1(h)",
"active_f"=>"17809", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"1", "id"=>"2", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10", "description"=>"10.00000000",
"catalog_number"=>"MEK1(h)", "km_conc"=>"126.00000000",
"ref_inhib_known_value"=>"14"}>, #<Kinase:0x251fdb4 @attributes=
{"ref_inhib_compound_id"=>"30", "name"=>"MAPK2(m)",
"active_f"=>"17802", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"30", "id"=>"3", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10",
"description"=>"155.00000000", "catalog_number"=>"MAPK2(m)",
"km_conc"=>"122.00000000", "ref_inhib_known_value"=>"14"}>]>

 >> #### the kinases were found!

As Mel said, our solution is to save the owner first, then add the
associations and save again.

For those who want more data, here's a longer segment of my console
output, with one that works and one that doesn't:

Create a new Recipe:

 >> r = Recipe.new
=> #<Recipe:0x2586820 @attributes={"name"=>nil,
"experiment_type_id"=>nil, "replicate_type_id"=>nil,
"description"=>nil, "workorder_id"=>nil}, @new_record=true>
 >> r.name = 'foo'
=> "foo"
 >> r.description = 'bar'
=> "bar"

Add some atp_concentrations (many to many)

 >> r.atp_concentration_ids=[1,2]
=> [1, 2]
 >> r
=> #<Recipe:0x2586820 @attributes={"name"=>"foo",
"experiment_type_id"=>nil, "replicate_type_id"=>nil,
"description"=>"bar", "workorder_id"=>nil}, @atp_concentrations=
[#<AtpConcentration:0x254c490 @attributes={"id"=>"1",
"description"=>"KM"}>, #<AtpConcentration:0x254c454 @attributes=
{"id"=>"2", "description"=>"10"}>], @new_record=true>
 >> r.save
=> true
 >> r.id
=> 15
 >> r = Recipe.find 15
=> #<Recipe:0x25377c0 @attributes={"name"=>"foo",
"experiment_type_id"=>nil, "replicate_type_id"=>nil, "id"=>"15",
"description"=>"bar", "workorder_id"=>nil}>
 >> r
=> #<Recipe:0x25377c0 @attributes={"name"=>"foo",
"experiment_type_id"=>nil, "replicate_type_id"=>nil, "id"=>"15",
"description"=>"bar", "workorder_id"=>nil}>
 >> r.atp_concentrations
=> [#<AtpConcentration:0x252fd2c @attributes=
{"atp_concentration_id"=>"1", "recipe_id"=>"15", "id"=>"1",
"description"=>"KM"}>, #<AtpConcentration:0x252fcf0 @attributes=
{"atp_concentration_id"=>"2", "recipe_id"=>"15", "id"=>"2",
"description"=>"10"}>]
 >> #### atp_concentrations worked fine on a Recipe.new.... r.save
?> #### now for a kinase:
?> r = Recipe.new
=> #<Recipe:0x252c94c @attributes={"name"=>nil,
"experiment_type_id"=>nil, "replicate_type_id"=>nil,
"description"=>nil, "workorder_id"=>nil}, @new_record=true>
 >> r.name = 'kinase recipe'
=> "kinase recipe"
 >> r.description = 'description'
=> "description"
 >> r.kinase_ids=[1,2,3]
=> [1, 2, 3]
 >> r
=> #<Recipe:0x252c94c @attributes={"name"=>"kinase recipe",
"experiment_type_id"=>nil, "replicate_type_id"=>nil,
"description"=>"description", "workorder_id"=>nil}, @new_record=true,
@kinases=[#<Kinase:0x251fe2c @attributes=
{"ref_inhib_compound_id"=>"10", "name"=>"c-RAF(h)",
"active_f"=>"17807", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"10", "id"=>"1", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10", "description"=>"45.00000000",
"catalog_number"=>"c-RAF(h)", "km_conc"=>"47.00000000",
"ref_inhib_known_value"=>"14"}>, #<Kinase:0x251fdf0 @attributes=
{"ref_inhib_compound_id"=>"1", "name"=>"MEK1(h)",
"active_f"=>"17809", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"1", "id"=>"2", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10", "description"=>"10.00000000",
"catalog_number"=>"MEK1(h)", "km_conc"=>"126.00000000",
"ref_inhib_known_value"=>"14"}>, #<Kinase:0x251fdb4 @attributes=
{"ref_inhib_compound_id"=>"30", "name"=>"MAPK2(m)",
"active_f"=>"17802", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"30", "id"=>"3", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10",
"description"=>"155.00000000", "catalog_number"=>"MAPK2(m)",
"km_conc"=>"122.00000000", "ref_inhib_known_value"=>"14"}>]>
 >> #### the kinases were found!
?> r.save!
=> true
 >> #### now let's refetch the data
?> r.id
=> 16
 >> r = Recipe.find 16
=> #<Recipe:0x250d830 @attributes={"name"=>"kinase recipe",
"experiment_type_id"=>nil, "replicate_type_id"=>nil, "id"=>"16",
"description"=>"description", "workorder_id"=>nil}>
 >> r.kinases
=> []
 >> #### they were not saved
?> #### but if I add them to this object and do an update, they will
?> r.kinase_ids=[1,2,3]
=> [1, 2, 3]
 >> r
=> #<Recipe:0x250d830 @attributes={"name"=>"kinase recipe",
"experiment_type_id"=>nil, "replicate_type_id"=>nil, "id"=>"16",
"description"=>"description", "workorder_id"=>nil}, @kinases=
[#<Kinase:0x2503010 @attributes={"ref_inhib_compound_id"=>"10",
"name"=>"c-RAF(h)", "active_f"=>"17807", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"10", "id"=>"1", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10", "description"=>"45.00000000",
"catalog_number"=>"c-RAF(h)", "km_conc"=>"47.00000000",
"ref_inhib_known_value"=>"14"}>, #<Kinase:0x2502fd4 @attributes=
{"ref_inhib_compound_id"=>"1", "name"=>"MEK1(h)",
"active_f"=>"17809", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"1", "id"=>"2", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10", "description"=>"10.00000000",
"catalog_number"=>"MEK1(h)", "km_conc"=>"126.00000000",
"ref_inhib_known_value"=>"14"}>, #<Kinase:0x2502f98 @attributes=
{"ref_inhib_compound_id"=>"30", "name"=>"MAPK2(m)",
"active_f"=>"17802", "sort_order"=>"1",
"ref_inhib_10atp_compound_conc"=>"30", "id"=>"3", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10",
"description"=>"155.00000000", "catalog_number"=>"MAPK2(m)",
"km_conc"=>"122.00000000", "ref_inhib_known_value"=>"14"}>]>
 >> r.save
=> true
 >> r.id
=> 16
 >> r = Recipe.find 16
=> #<Recipe:0x24ef90c @attributes={"name"=>"kinase recipe",
"experiment_type_id"=>nil, "replicate_type_id"=>nil, "id"=>"16",
"description"=>"description", "workorder_id"=>nil}>
 >> r.kinases
=> [#<Kinase:0x24eb0dc @attributes={"ref_inhib_compound_id"=>"10",
"name"=>"c-RAF(h)", "active_f"=>"17807", "sort_order"=>"1",
"kinase_id"=>"1", "recipe_id"=>"16",
"ref_inhib_10atp_compound_conc"=>"10", "id"=>"1", "simple_name"=>nil,
"ref_inhib_100atp_compound_conc"=>"10", "description"=>"45.00000000",
"catalog_number"=>"c-RAF(h)", "km_conc"=>"47.00000000",
"ref_inhib_known_value"=>"14"}>, #<Kinase:0x24eb0a0 @attributes=
{"ref_inhib_compound_id"=>"1", "name"=>"MEK1(h)",
"active_f"=>"17809", "sort_order"=>"1", "kinase_id"=>"2",
"recipe_id"=>"16", "ref_inhib_10atp_compound_conc"=>"1", "id"=>"2",
"simple_name"=>nil, "ref_inhib_100atp_compound_conc"=>"10",
"description"=>"10.00000000", "catalog_number"=>"MEK1(h)",
"km_conc"=>"126.00000000", "ref_inhib_known_value"=>"14"}>, #<Kinase:
0x24eb064 @attributes={"ref_inhib_compound_id"=>"30", "name"=>"MAPK2
(m)", "active_f"=>"17802", "sort_order"=>"1", "kinase_id"=>"3",
"recipe_id"=>"16", "ref_inhib_10atp_compound_conc"=>"30", "id"=>"3",
"simple_name"=>nil, "ref_inhib_100atp_compound_conc"=>"10",
"description"=>"155.00000000", "catalog_number"=>"MAPK2(m)",
"km_conc"=>"122.00000000", "ref_inhib_known_value"=>"14"}>]
 >>
0895305feb2b97049c39b08972233d02?d=identicon&s=25 Anthony Rudgick <arudgick@gmail.com> (Guest)
on 2005-12-14 00:20
can someone post a code example of the best method to save the parent
then do the habtm relations?

thanks from this designer masquerading as a programmer,
-A
7a966bb1534f0ea863bc9ffe65ae449f?d=identicon&s=25 Jamie Orchard-Hays (Guest)
on 2005-12-14 01:55
(Received via mailing list)
Mel put this in our code base earlier. I've abbreviated the final save:

@recipe = Recipe.new(params[:recipe])
@recipe.save!
# Ruby has a simple definition of truth. Any value that is not nil or
the constant false is true.
# update any associations defined:
@recipe.kinase_ids = @params[:kinase_ids] == nil ? Array.new : @params
[:kinase_ids]
if@recipe.save
   #go where you want
else
  #go where you want
end
Cb610750ee94ca103aef4b2dc7b1b768?d=identicon&s=25 Nick Stuart (Guest)
on 2005-12-15 21:56
Yep, just ran into this.

Its always the first HABTM relationship that saves. If I reorder them
the first one will save, but not the others. Really odd, but just
confirming this is the current behavior.

>
> So I went from 'Why aren't the other HABTMs saving?' to 'Why is that one
> HABTM saving?'
>
> Has anyone else experienced this situation?
>
> Mel
This topic is locked and can not be replied to.