I have two models, quiz and quiz_question, where quiz_question belongs
to quiz. If i change the foreign key, the named association doesn't
update. Can i force it to?
Ideally, here, when i change question_id (but don't yet save) i'd like
the .question method to return question 473, not 474. Is there a method
i can call to make the named association update itself based on the
foreign key?
You're better off working with Rails, rather than against it, and
instead of setting the foreign key attribute, pass the new object that
you want associated.
instead of
quiz_question.question_id = 473
do this
quiz_question.question = Question.find(473)
ActiveRecord will handle the db field updates - that's what it's there
for. You just worry about the objects
Hi Michael - i kind of expected that kind of reply
The reason that i'm doing it in this case is that i've overridden the
set method for one of my foreign keys to do some other stuff after
changing the foreign key. But, it just occurred to me that a better way
to handle that is via a dirty models sort of approach of not getting
involved in the set method but detecting the change instead. What's the
simplest way to do that, do you know?
Hi Michael - i kind of expected that kind of reply
If you've got special reasons why you think you need to pursue the
route you have, it would help if you mention those in your initial
post.
Anyway...
The reason that i'm doing it in this case is that i've overridden the
set method for one of my foreign keys to do some other stuff after
changing the foreign key. But, it just occurred to me that a better way
to handle that is via a dirty models sort of approach of not getting
involved in the set method but detecting the change instead. What's the
simplest way to do that, do you know?
My first thought was "What's stopping you overloading the set method
for the associated object? And move your other stuff code into that
method." But then I recalled I'd try to do that myself in the past,
and hit a brick wall. So I've spent the evening fiddling, and hit the
same wall again. Can't seem to get the Rails association magic to
fire, as the methods for the associations are created when the class
is created.
So all I can think is you have two options (one generates smellier
code than the other):
1) use the overloaded foreign_key_id method that you are at the moment
(which smacks of bypassing the functionality that Rails gives you) and
set the model's associated object to nil before doing your stuff (this
does work)
2) create a new method (something along the lines of "set_question")
which does both the setting of the associated object through the
normal "question" method, and does your stuff too.
I do wonder if there's a third way that might be a better solution for
you, but which depends on the specifics of the "other stuff" that
you're doing - it may be that this "other stuff" might be done
elsewhere maybe.
What's occurring to me now is that because there are two routes to
achieve the same thing (changing the associated value through either
the association accessors or through the foreign_key_id field; if you
change one to do some application magic, you've got to be very careful
to *never* call the other method, or else your magic won't happen and
your application will do funny stuff.
So I'd definitely be looking for the third way!
I ended up doing your second suggestion, shying away from the rails
magic since i couldn't seem to really control it.
Personally it seems most natural to me for rails to work the association
magic when either the foreign key is changed or the direct association
set method is called. I was hunting around and there's various
discussions about this on rails development forums but i guess it never
got resolved, or the rails gods decided against it.
Hi Michael - i kind of expected that kind of reply
The reason that i'm doing it in this case is that i've overridden the
set method for one of my foreign keys to do some other stuff after
changing the foreign key. But, it just occurred to me that a better way
to handle that is via a dirty models sort of approach of not getting
involved in the set method but detecting the change instead. What's the
simplest way to do that, do you know?
OT: This is a slightly off-topic reply, but this really makes me
appreciate Key Value Observing (KVO) from the world of Cocoa.
If Rails had such a mechanism you could register to observe changes to
the relationship and perform your additional stuff anytime a change was
detected. Well, one can dream anyway.
Wouldn't ActiveRecord Observer class do what you're looking for?
Observer has the same problem as callbacks - you can only hook them into
database transactions. I'm talking about the situation when you've
changed something and go on to do some other things without saving yet.
Also (just as a thought experiment), you would have to jump through
lots of hoops to try to figure whether it was the foreign_key that was
changed, or the associated object.
With callbacks, you can only see that the two things are different,
but not which one is most recent.