ruby-on-railsrubyformsmodelform-for

How to update model field from another model field


I have two models

    class Owner < ActiveRecord::Base
     has_many :dogs
    end
    
    class Dog < ActiveRecord::Base
      belongs_to :owner
      accepts_nested_attributes_for :owner
      before_validation :set_name

      private
      def set_name
        self.name = owner.name
      end
    end

and after submitting a form (and therefore calling before_validation :set_name), I want to update the Dog name to be the Owner name.

Moreover, My question is: what's the correct formatting of self.name = owner.name?

My form looks like this:

    <h1>Create a new Dog:</h1>
    <%= form_for(@dog) do |f|%>
        
      <div>
        <%= f.label :breed%>
        <%= f.text_field :breed%>
      </div><br>
        
      <div>
        <%= f.label :age%>
        <%= f.text_field :age%>
      </div><br>
        
        <div>
        <h3>Create a new owner:</h3>
         <%= f.fields_for :owner, Owner.new do |owner_attributes|%>
          <%= owner_attributes.label :name, "Owner Name:" %>
          <%= owner_attributes.text_field :name %>
         <% end %>
        </div>
        
      <%= f.submit %>
        
    <% end %>

You can see that the Dog doesn't have a text_field for a name, and this is because I want the owner name to be the dog's name. Thanks for the help!


Solution

  • In order to keep things in sync, without needing to store the name of the owner on the dog object, I would suggest moving away from having an attribute on the dog class for the name, and instead use ActiveSupport::Delegate functionality to delegate the name call on an instance of a Dog to the Owner it belongs to. This would look like:

    class Dog
      belongs_to :owner
      delegates :name, to: :owner
    end
    

    The above code creates a thin name method on the Dog instance that simply calls owner.name. This way no matter what the owner changes the name to, the dogs name is always derived from the owner.