Как я использую accepts_nested_attributes_for?

Редактирование моего вопроса для краткости и обновить то, что я сделал:

Как я моделирую наличие нескольких Адресов для Компании и присваиваю единственный Адрес Контакту и могу присвоиться им при создании или редактировании Контакта?

Я хочу использовать вложенные атрибуты, чтобы смочь добавить адрес во время создания нового контакта. Тот адрес существует как своя собственная модель, потому что я могу хотеть опцию к выпадающему от существующих адресов вместо того, чтобы войти с нуля.

Я, может казаться, не заставляю это работать. Я получаю неопределенный метод 'сборка' для nil:NilClass ошибки

Вот моя модель для Контактов:

class Contact < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :title, :phone, :fax, :email, :company, 
                  :date_entered, :campaign_id, :company_name, :address_id, :address_attributes

  belongs_to :company
  belongs_to :address
  accepts_nested_attributes_for :address
end

Вот моя модель для Адреса:

class Address < ActiveRecord::Base
  attr_accessible :street1, :street2, :city, :state, :zip

  has_many :contacts
end

Я хотел бы, при создании нового контакта, доступ все Адреса, которые принадлежат другим Контактам, которые принадлежат Компании. Таким образом, вот то, как я представляю Компанию:

class Company < ActiveRecord::Base
  attr_accessible :name, :phone, :addresses

  has_many :contacts

  has_many :addresses, :through => :contacts

end

Вот то, как я пытаюсь создать поле в Представлении для _form для Контакта так, чтобы, когда кто-то создает новый Контакт, они передали адрес модели Address и партнеру, которые адресуют к Контакту:

  <% f.fields_for :address, @contact.address do |builder| %>
  <p>
    <%= builder.label :street1, "Street 1" %> </br> 
    <%= builder.text_field :street1 %>
  <p>
  <% end %>

Когда я пытаюсь Отредактировать, поле для улицы 1 является пробелом. И я не знаю, как отобразить значение от show.html.erb.

Внизу моя ошибочная консоль - может казаться, не создает стоимость в таблице адресов:

Мой контроллер Контактов следующие:

  def new
    @contact = Contact.new
    @contact.address.build # Iundefined method `build' for nil:NilClass

    @contact.date_entered = Date.today
    @campaigns = Campaign.find(:all, :order => "name")
    if params[:campaign_id].blank? 

    else
      @campaign = Campaign.find(params[:campaign_id])
      @contact.campaign_id = @campaign.id
    end

    if params[:company_id].blank?

    else
      @company = Company.find(params[:company_id])
      @contact.company_name = @company.name
    end

  end

  def create
    @contact = Contact.new(params[:contact])
    if @contact.save
      flash[:notice] = "Successfully created contact."
      redirect_to @contact
    else
      render :action => 'new'
    end
  end

  def edit
    @contact = Contact.find(params[:id])
    @campaigns = Campaign.find(:all, :order => "name")
  end

Вот отрывок моей ошибочной консоли: Я ОТПРАВЛЯЮ атрибут, но он не СОЗДАЕТ в Таблице адресов....

Обработка ContactsController#create (для 127.0.0.1 в 12.05.2010 21:16:17)

[POST] Параметры: {"фиксация" => "Отправляет", "authenticity_token" => "d8/gx0zy0Vgg6ghfcbAYL0YtGjYIUC2b1aG+dDKjuSs = ", "связывается" => {"company_name" => "Allyforce", "заголовок" =>"", "campaign_id" => "2", "address_attributes" => {"street1" => "abc"} ", факс" =>"", "звонят" =>"" ", last_name" =>"" ", date_entered" => "2010-05-12", "электронная почта" =>"" ", first_name" => "abc" }}

Загрузка компании (0,0 мс) [0m [0mSELECT * ОТ "компаний", ГДЕ ("компании". "назовите" = 'Allyforce'), ОГРАНИЧИВАЮТ 1 [0m

Адрес создает (16,0 мс) [0m
[0; 1mINSERT В "адреса" ("город", "zip", "created_at", "street1", "updated_at", "street2", "состояние") ЗНАЧЕНИЯ (ПУСТОЙ УКАЗАТЕЛЬ, ПУСТОЙ УКАЗАТЕЛЬ, '13.05.2010 4:16:18', ПУСТОЙ УКАЗАТЕЛЬ, '13.05.2010 4:16:18', ПУСТОЙ УКАЗАТЕЛЬ, ПУСТОЙ УКАЗАТЕЛЬ) [0m

Контакт создает (0,0 мс) [0m
[0mINSERT В "контакты" ("компания", "created_at", "заголовок", "updated_at", "campaign_id", "address_id", "last_name", "телефон", "факс", "company_id", "date_entered", "first_name", "электронная почта") ЗНАЧЕНИЯ (ПУСТОЙ УКАЗАТЕЛЬ, '13.05.2010 4:16:18', '', '13.05.2010 4:16:18', 2, 2, '' '', '', 5, '2010-05-12', 'abc', '') [0m

5
задан Timothy T. 14 May 2010 в 01:39
поделиться

4 ответа

Просто банальный вопрос, если вы используете это в контактной форме, разве адрес не должен быть в единственном числе?

 <% f.fields_for :address, @contact.address do |builder| %>
   <p>
     <%= builder.label :street1, "Street 1" %> </br> 
     <%= builder.text_field :street1 %>
   <p>
 <% end %>

В вашем действии вы также должны сделать

@ycontact.build_address

Если вы посмотрите на исходный код, ваше поле ввода должно выглядеть так.

< input type="text" size="30" name="contact[address_attributes][street1]" id="contact_address_attributes_street1">

Я думаю, что у вас также есть проблемы с ассоциациями, если вы храните address_id в контакте, то

class Contact < ActiveRecord::Base
  belongs_to :address
  accepts_nested_attributes_for :address
end

class Address < ActiveRecord::Base
  attr_accessible :street1
  has_many :contacts
end

И я думаю, что это ваш случай, потому что вы хотите назначить адрес нескольким контактам.

Вы также можете сделать наоборот, если вы храните contact_id в вашей модели адреса:

class Contact < ActiveRecord::Base
  has_one :address
  accepts_nested_attributes_for :address
end

class Address < ActiveRecord::Base
  attr_accessible :street1
  belongs_to :contact
end

В этом случае вы не можете иметь пользователей с одинаковым адресом.

Обновление

В пользовательском show.html.eb вы можете использовать

<%= @contact.address.street1 %>

В show.html.erb вашей компании вы можете отображать адреса так:

<% @company.addresses.each do |address| %>
  <%= address.street1 %>
  ...
<% end %>

На странице редактирования пользователя поля формы должны быть такими же, как в new.html.erb, только тег формы должен выглядеть так:

<% form_for @contact do |form| %>
  <%=render :partial=>'fields' %>
<% end %>

Поля partial содержат все ваши фиды вместе с:

 <% f.fields_for :address, @contact.address do |builder| %>
   <p>
     <%= builder.label :street1, "Street 1" %> </br> 
     <%= builder.text_field :street1 %>
   <p>
 <% end %>

Это должно работать.

Обновление 2

Вы можете получить доступ ко всем адресам, принадлежащим компании с помощью:

@company.addresses

Если у вас есть

class Company<Activerecord::Base
    has_many :contacts
    has_many :addresses, :through=>:contacts
end

О черновиках или адресах по умолчанию. Вы можете использовать различные варианты в зависимости от ваших потребностей. Мне нужна возможность, чтобы контакт мог выбрать один из существующих адресов из базы данных. Вы можете сделать поле выбора в вашей контактной форме, например:

 <%= form.select :address_id, options_from_collection_for_select(@company.addresses, 'id', 'street1')%>

Также вы можете использовать некоторые фантазии javascript для добавления или удаления формы адреса, в этом случае, если пользователь выбирает один из существующих адресов. В этом случае вам придется удалить address_attributes из формы. Я предлагаю создать ссылку с кодом javascript, который добавляет адресные_атрибуты и удаляет (стиль переключения).

3
ответ дан 14 December 2019 в 19:06
поделиться

Я бы рекомендовал позволить Контакту иметь много адресов. Это происходит в любом случае. Если решено, что только один, то это будет has_one :address

О, и вы должны уменьшить их: has_many :Contacts должно быть has_many :contacts

В модели адресов, на которую вы ссылаетесь (базе данных нужны поля addressable_id и addressable_type)

belongs_to :addressable, :polymorphic => true
0
ответ дан 14 December 2019 в 19:06
поделиться

Если каждый адрес принадлежит только одному контакту (например, домашний адрес), вы можете сделать:

class Company < ActiveRecord::Base
  has_many :contacts
end

class Contact < ActiveRecord::Base
  belongs_to :company
  has_one :address
end

class Address < ActiveRecord::Base
  belongs_to :contact
end

Конечно, вы можете просто переместить столбцы адресов в таблицу контактов и полностью избавиться от модели адреса.

Если каждый адрес имеет несколько контактов (т. Е. Адреса являются объектами компании, где работают контакты):

class Company < ActiveRecord::Base
  has_many :contacts
end

class Contact < ActiveRecord::Base
  belongs_to :company
  belongs_to :address
end

class Address < ActiveRecord::Base
  has_many :contacts
end

Вы можете добавить ассоциацию has_many: через , чтобы получить company.addresses ]:

class Company < ActiveRecord::Base
  has_many :contacts
  has_many :addresses, :through => :contacts
end

В обоих случаях компоненты адреса (улица, город, штат и т. Д.) Являются столбцами в таблице адресов.

Последняя часть вашего вопроса действительно зависит от распределения данных - если у вас всего несколько адресов, вы можете просто вставить их в элемент select с основным адресом по умолчанию. При большем количестве адресов вам может потребоваться форма AJAXified с автозаполнением для поиска в таблице адресов.

Чтобы добавить новые контакты / адреса в таблицы, вы можете просмотреть вложенные формы. Railscast 196 - хорошее введение.

РЕДАКТИРОВАТЬ - подробнее о вложенных атрибутах

accept_nested_attributes_for должен работать с ассоциацией has_many или has_one и должен работать с несколькими уровнями вложенности. Похоже, вы хотите, чтобы контакт принадлежал компании, а адрес - контакту. В этом случае:

class Company < ActiveRecord::Base
  has_many :contacts
  accepts_nested_attributes_for :contact
end

class Contact < ActiveRecord::Base
  belongs_to :company
  has_one :address # or has_many, if you prefer
end

class Address < ActiveRecord::Base
  belongs_to :contact
end

Затем в представлении используйте form_for и fields_for как описано в Railscast, чтобы получить вложенные элементы формы. Это может быть немного сложно сделать правильно, если ваша форма необычна.Здесь есть отличные примеры от ryanb , которые охватывают несколько типичных ситуаций.

1
ответ дан 14 December 2019 в 19:06
поделиться

Поскольку вы хотите, чтобы адрес принадлежал и компании, и контакту, у вас есть два варианта.Если вам никогда не понадобится несколько адресов (что я бы не рекомендовал предполагать), вы можете указать «own_to: address» как в Company, так и в контакте. Тогда адрес будет иметь как «has_many: companies», так и «has_many: contacts».

Лучшим вариантом, который имеет больше смысла, является использование полиморфных ассоциаций, где таблица адресов будет иметь столбцы: addressable_type и: addressable_id для обратной связи с любой моделью.

class Company < ActiveRecord::Base
  attr_accessible :name, :phone, :addresses

  has_many :contacts  
  accepts_nested_attributes_for :contacts

  has_many :addresses, :as => :addressable
  accepts_nested_attributes_for :addresses

end

class Contact < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :title, :phone, :fax, :email, :company, 
                  :date_entered, :campaign_id, :company_name

  belongs_to :company
  has_many :addresses, :as => :addressable
  accepts_nested_attributes_for :addresses
end

class Address < ActiveRecord::Base
  attr_accessible :street1

  belongs_to :addressable, :polymorphic => true
end

Теперь ваша проблема связана с желанием иметь единую ассоциацию "company.addresses", чтобы получить как ее адрес, так и адреса ее контактов. Я мог бы порекомендовать держаться подальше от этого и использовать другой подход.

Вам нужно сопоставить эти адреса в представлении с правильной записью, поэтому лучше всего их разделить:

<% form_for @company do |company_form| %>
  <% company_form.fields_for :addresses do |address_form| %>
    <%= address_form.text_field :street1 %>
  <% end %>
  <% company_form.fields_for :contacts do |contact_form| %>
    <% contact_form.fields_for :addresses do |contact_address_form| %>
      <%= contact_address_form.text_field :street1 %>
    <% end %>
  <% end %>
<% end %>

В вашей таблице адресов есть полиморфные столбцы, подобные этому:

class CreateAddresses < ActiveRecord::Migration
  def self.up
    create_table :addresses do |t|
      t.string :street1
      t.string :addressable_type
      t.integer :addressable_id
      t.timestamps
    end
  end

  def self.down
    drop_table :addresses
  end
end

Я не конечно, как вы могли бы сохранить все ссылки прямо, если вы не вкладываете записи по отдельности, как это.

Если вам действительно нужно получить все адреса компании для отображения, вы можете использовать стандартные манипуляции с перечислением ruby, такие как сбор, чтобы собрать их вместе.

Удачи!

1
ответ дан 14 December 2019 в 19:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: