RamJet
RamJet

Reputation: 303

how to write collection_select with nested attributes in Rails

I have a model with nested attributes. I can't get collection_select to work. Here's what I have

class Client < ActiveRecord::Base
  belongs_to :contact
  belongs_to :person, dependent: :destroy
  accepts_nested_attributes_for :person, allow_destroy: true
end

class Contact < ActiveRecord::Base
  has_many :clients
  belongs_to :person, dependent: :destroy
  accepts_nested_attributes_for :person, allow_destroy: true
end

class Person < ActiveRecord::Base
  has_one :client
  has_one :contact
  belongs_to :personal_title
  # Returns the combined personal title, first and surname
  def name
    [
      personal_title.nil? ? '' : personal_title.title,
      first_name || '',
      last_name || ''
    ].reject(&:empty?).join(' ')
  end
end

In summary, Client has a contact_id and a person_id, Contact has a person_id and Person has a personal_title_id. On my form I have

<div class="field">
  <%= f.label :contact_id %><br>
  <%= f.collection_select(:contact_id, Client.all, :id, :name,
    {include_blank: true}) %>
</div>

I know where the problem is, but from the documentation I can't work out how to fix it. The error I get is undefined method 'name' for #<Client:0x6c01350>. That's correct. name() is declared in Person, not Client. I can get it to work with,

<select name="client[contact_id]">
  <% Contact.all.each do |contact| %>
    <option value="<%= contact.id %>"><%= contact.person.name %></option>
  <% end %>
</select>

This works because I have used contact.person.name, not contact.name.

Upvotes: 1

Views: 408

Answers (1)

dthal
dthal

Reputation: 1023

In the model Client isnt a method to return the name. The method to return the name is in the Person class.

Create a method in Client to return the name of the person and it should be work.

class Client < ActiveRecord::Base
  belongs_to :contact
  belongs_to :person, dependent: :destroy
  accepts_nested_attributes_for :person, allow_destroy: true

  def name
    self.person.name
  end

end

Upvotes: 1

Related Questions