Reputation: 2775
Edit: Clarifications added
Given the following two classes
class Foo < ActiveRecord::Base
belongs_to :bar
end
class Bar < ActiveRecord::Base
end
When I change a bar on a foo, I would like a way to see that the foo instance has changed:
foo = Foo.find(x)
foo.bar # returns #<Bar id:1>
foo.bar = Bar.new
foo.changed? # returns false
foo.changes # returns an empty hash
I don't want to set bar_id as dirty (because it hasn't changed) It would be nice to have the following:
foo.changed? # returns true
foo.changes # returns {:bar => [#<Bar id: 1>, nil]}
Is there a clever way to hack this into Rails? Is there a reason this is not part of Rails?
Upvotes: 3
Views: 5694
Reputation: 7101
Due to changes to @changed_attributes
in Rails 5.1, I had to resort to using a virtual attribute (attr_accessor) to indicate the changed association after checks. This might be better in the long run compared to messing with Rails internals related to ActiveRecord::Dirty
Upvotes: 0
Reputation: 106
I faced the same problem today and after running through the rails-source i found a workaround that should do what you had in mind, if i got your question the right way.
Transferred to your example the code should look like that:
class Foo < ActiveRecord::Base
belongs_to :bar
def info
bar.info
end
def info=(val)
@changed_attributes[:info] = self.info unless val == self.info
self.time_entry.update_attributes! :info => val
end
end
class Bar < ActiveRecord::Base
attr_accessible :info
end
This way you can call .changed? and .changes on objects of the Foo-class.
hope this helps even if the answer comes a bit late :)
kind regards christian
btw. sorry for the poor english. i am working on that as much as on my ruby-skills ;)
Upvotes: 3
Reputation: 4003
What version of Rails are you using? When I tested it, it does report true.
Anyway, I am not sure if an after assign callback is available for belongs_to yet. There was a ticket for this https://github.com/rails/rails/issues/586
If not, you can just override the assign method (I haven't tried this before, but I think it will work :) so please let me know)
class Foo < ActiveRecord::Base
belongs_to :bar
def bar=(b)
bar_id_will_change! unless bar_id == b.id
super
end
end
Update: Just read your question again, and I am not even sure if I understood all of it. You want it to still report true if it hasn't changed? Even when assigning the same object again right? in which case you can remove the unless bar_id == b.id
part
Upvotes: 2