I'm trying to access my parent model in my child model when validating. I found something about an inverse property on the has_one, but my Rails 2.3.5 doesn't recognize it, so it must have never made it into the release. I'm not sure if it's exactly what I need though.
I want to validate the child conditionally based on parent attributes. My Parent model has already been created. If the child hasn't been created when I update_attributes on the parent, then it doesn't have access to the parent. I'm wondering how I can access this parent. It should be easy, something like parent.build_child sets the parent_id of the child model, why is it not doing it when building the child for accepts_nested_attributes_for?
For Example:
class Parent < AR
has_one :child
accepts_nested_attributes_for :child
end
class Child < AR
belongs_to :parent
validates_presence_of :name, :if => :some_method
def some_method
return self.parent.some_condition # => undefined method `some_condition' for nil:NilClass
end
end
My form is standard:
<% form_for @parent do |f| %>
<% f.fields_for :child do |c| %>
<%= c.name %>
<% end %>
<% end %>
With an update method
def update
@parent = Parent.find(params[:id])
@parent.update_attributes(params[:parent]) # => this is where my child validations take place
end
I had basically the same problem with Rails 3.2. As suggested in the question, adding the inverse_of
option to the parent's association fixed it for me.
Applied to your example:
class Parent < AR
has_one :child, inverse_of: :parent
accepts_nested_attributes_for :child
end
class Child < AR
belongs_to :parent, inverse_of: :child
validates_presence_of :name, :if => :some_method
def some_method
return self.parent.some_condition # => undefined method `some_condition' for nil:NilClass
end
end
I had a similar problem: Ruby on Rails - nested attributes: How do I access the parent model from child model
This is how I solved it eventually; by setting parent on callback
class Parent < AR
has_one :child, :before_add => :set_nest
accepts_nested_attributes_for :child
private
def set_nest(child)
child.parent ||= self
end
end
You cannot do this because in-memory child doesn't know the parent its assigned to. It only knows after save. For example.
child = parent.build_child
parent.child # => child
child.parent # => nil
# BUT
child.parent = parent
child.parent # => parent
parent.child # => child
So you can kind of force this behavior by doing reverse association manually. For example
def child_with_inverse_assignment=(child)
child.parent = self
self.child_without_inverse_assignment = child
end
def build_child_with_inverse_assignment(*args)
build_child_without_inverse_assignment(*args)
child.parent = self
child
end
def create_child_with_inverse_assignment(*args)
create_child_without_inverse_assignment(*args)
child.parent = self
child
end
alias_method_chain :"child=", :inverse_assignment
alias_method_chain :build_child, :inverse_assignment
alias_method_chain :create_child, :inverse_assignment
If you really find it necessary.
P.S. The reason it's not doing it now is because it's not too easy. It needs to be explicitly told how to access parent/child in each particular case. A comprehensive approach with identity map would've solved it, but for newer version there's :inverse_of
workaround. Some discussions like this one took place on newsgroups.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With