Association collections problems

Hi all!

I find association collections to be quite hard to understand and use.

I have a Leg class that has_many :choices, and a Choice class that
belongs_to :leg. In a controller I want to update both a Leg and its
Choices. If I do it like this:

@leg.choices.update params[:choice].keys, params[:choice].values

It updates the database directly (or more specifically only updates
records that validates). So if I want to make the update to the @leg and
@leg.choices as an atomic action I guess that I will have to introduce a
transaction. However, then all the changes will be lost for the user
since the form will reflect the unchanged database, right?

So then I tried to first make the updates to the choices and then save
everything in a transaction, like this:

@leg.attributes = params[:leg]
choices = params[:choice]
if choices
choices.each do |key, value|
@leg.choices.find(key).attributes = value
end
end
if request.post?
Leg.transaction do
@leg.save!
@leg.choices.each {|choice| choice.save! }
end

But it tuns out that I can’t make changes to individual records in the
association collection, so the @leg.choices.find().attributes=() doesn’t
change anything.

So now I’m basically out of ideas. Does anyone got any pointers?

Thanks in advance!
/Jonas

Anyone?

/Jonas

jonas wrote:

I find association collections to be quite hard to understand and use.

First of all, when you do @leg.choices.find(key).attributes = value,
you’re asking Rails to query the database for a new instance of that
particular choice and set the attributes on that. You then discard
this new instance without saving it.

But I’m not really sure what you’re trying to do. As far as I can
see, there’s no update method on a has_many relationship, so your
first bit of code shouldn’t work. Can you give a concrete example of
what your params might consist of, and how you expect the database to
be changed as result?

Cheers,

Pete Y.

Thanks for taking the time to respond Pete!

Yes, I thought that @leg.choices.find would not fetch new records from
the database but find one of records that are already fetched from the
database.

@leg.choices.update did work, but not the way I wanted and I can’t find
the documentation for it.

To rehash/clarify the problem:
I have Leg that has_many :choices, and Choice that belongs_to :leg. For
this example Tag has :this as an attribute, and Choice got :that. Before
the action the database looks like this:
legs
[id=1, this=“Hello”]
choices
[id=1, leg_id=1, that=“World”]
[id=2, leg_id=1, that=“Europe”]
The parameters look like this:
{
“leg”=> {“this”=>“Hi”},
“choice”=>
{
“1”=>{“that”=>“y’all”},
“2”=>{“that”=>“everyone”}
}
}
After the action I want the database to look like this:
legs
[id=1, this=“Hi”]
choices
[id=1, leg_id=1, that=“y’all”]
[id=2, leg_id=1, that=“everyone”]

I seem to have found a way that works now, however I must be missing
something since it requires way too many lines of code :slight_smile:

If I change the association collection to a regular Array, it behaves
the way I thought it would originally. I then update the choices with
the values from the parameters. And lastly I save everything.

@leg.attributes = params[:leg]

if params[:choice]
  choices = @leg.choices.to_a
  params[:choice].each do |key, value|
    choice = choices.find {|c| c.id.to_s == key}
    choice.attributes = value if choice
  end
end

if request.post?
  Leg.transaction do
    err = [email protected]
    @leg.choices.each {|choice| err ||= !choice.save }
    raise if err
  end
end

This seems to work, but is there an easier way?

/Jonas

pete wrote:

First of all, when you do @leg.choices.find(key).attributes = value,
you’re asking Rails to query the database for a new instance of that
particular choice and set the attributes on that. You then discard
this new instance without saving it.

But I’m not really sure what you’re trying to do. As far as I can
see, there’s no update method on a has_many relationship, so your
first bit of code shouldn’t work. Can you give a concrete example of
what your params might consist of, and how you expect the database to
be changed as result?

Cheers,

Pete Y.