简体   繁体   中英

Finding a particular instance in an associated model in Rails?

I have two models

class Owner < ActiveRecord::Base
 has_many :dogs
end

class Dog < ActiveRecord::Base
  belongs_to :owner
  accepts_nested_attributes_for :owner
end

and the tutorials I've seen always created a new instance (through build) of the associated model (@dog.build_owner in the code below)

class DogsController < ApplicationController
  def new
   @dog = Dog.new
   @dog.build_owner 
  end
 end

Is there a way to find an existing model instance (a particular owner in this case) and associate it when creating a new Dog? instead of creating a new owner every time.

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 %>

Thank you!

It looks like what you want to use here is ActiveRecord::Relations#find_or_create_by . In your controller, you'll get the name of the owner through your form, and you'll pass that into the find_or_create_by method like so:

@dog = Dog.new
@dog.owner.find_or_create_by(name: params.dig(:owner, :name))

This method will set the owner of the new instance of Dog to either the Owner that already exists with the name provided, or go ahead and create the new entry in the database and assign the association for you.

Something you probably want to do with this too is to go ahead and make sure that Owner#name is forced to be unique. find_or_create_by makes some pretty strong assumptions that there will only every be one instance of what you're looking for, so if there are multiple, you can get indeterminate results. To guarantee uniqueness of name in the Owner class, you add the following validation

class Owner < ActiveRecord::Base
 has_many :dogs

 # uniqueness validation of name
 validates :name, uniqueness: true
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM