1

I have two models, Dog and Owner, and I want their names to be the same, and would be redundant if I asked to fill out the fields twice (once for the dog and another time for the owner). I'm wondering if there's a simpler way to update the two databases with one input.

<h1>Create a new Dog:</h1>
<%= form_for(@dog) do |f|%>
  <div>
    <%= f.label :name%>
    <%= f.text_field :name%>
  </div><br>
    
  <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 %>

2 Answers2

1

First of all, not sure why you want to keep the name of the owner and the dog same.

However, there can be many ways to achieve what you want:

  1. You can simply omit the owner name from the form.

So you no longer need: <%= owner_attributes.label :name, "Owner Name:" %> OR you no longer need:

<div>
    <%= f.label :name%>
    <%= f.text_field :name%>
  </div><br>

And in the Owner/Dog model, you can pass the name of the dog/owner in a callback - maybe after_initialize or before_save or before_validation depending on your validation requirements.

class Dog
  belongs_to :owner
  before_validation :set_name

  private

  def set_name
    self.name = owner&.name
  end
end
  1. You can make the owner name as a hidden field instead and can write some javascript to update the hidden field with the dog name before submitting the form or onblur event. I would prefer the first approach since it's simpler and more secure than only JS solution to maintain database consistency
udit mittal
  • 529
  • 3
  • 14
  • Thanks for the answer! I have a question(I'm new to rails): How exactly does self.name = owner.name work? My controller has a `def new` where `@dog = Dog.new` and `@dog.build_owner`. I'm assuming that after the form is submitted, an association is automatically created between the `@dog` and `@dog.build_owner`, and this ultimately calls the before_validation in the class Dog which calls the set_name. Is this trace correct? – Lee Sung Hye Jul 19 '20 at 06:02
  • Also, is the & in `owner&.name` a typo in your answer? If not, would appreciate the help on learning the functionality! – Lee Sung Hye Jul 19 '20 at 06:04
0

If dogs belongs_to and owner, you don't really need to store the owner's name separately. You can just call dog.owner.name anywhere you have a Dog instance. Having said that, it is relatively straightforward to append attributes on top of the POSTed form values in your controller using .merge():

def create
  @dog = Dog.new(dog_params.merge(owner: params[:dog][:owner])[:name])
  if @dog.save
    ...
  end
end

def dog_params
  params.require(:dog).permit(:name, :breed, :age, owner: %i[name])
end
rmlockerd
  • 3,776
  • 2
  • 15
  • 25