рельсы: как добавить дочернюю ассоциацию через текстовое поле? - PullRequest
1 голос
/ 23 января 2010

У меня есть две модели: Компания и Персона

class Person < ActiveRecord::Base
 belongs_to :company
end

class Company < ActiveRecord::Base
  has_many :people
  accepts_nested_attributes_for :people, :allow_destroy => true, :reject_if => proc {|attrs| attrs.all? {|k,v| v.blank? } }
end

И моя частичная HTML-форма для новых и редактируемых действий выглядит следующим образом:

<% form_for(@company) do |company_f| %>
  <p>
    <b>Name</b><br />
    <%= company_f.text_field :name %>
  </p>

  <ul>
    <%= render :partial => 'person_fields', :collection => @company.people, :locals => {:company_f => company_f} %>
    <%= link_to_add_fields(:people, company_f) %>
  </ul>

  <p>
    <%= company_f.submit "Submit" %>
  </p>
<% end %>

, где частичное "_person_fields" выглядит какthis:

<li>
  <% company_f.fields_for :people, person_fields do |person_f| %>
    <%= person_f.label :name %>
    <%= person_f.text_field :name %>
  <% end %>
</li>

В настоящий момент, если я введу person_f.text_fiel: назовите имя человека и нажмите «Сохранить», будет создана новая модель Person с таким именем.Не то, что я хочу вообще, у меня уже есть модель человека этого человека в базе данных, я скорее хочу ассоциировать этого человека в этой компании.

Другое дело, что я не возражаю, используя имя для дружественной идентификации человека вместо идентификатора, подобного этому, для частичного "_person_fields"

<li>
  <% company_f.fields_for :people, person_fields do |person_f| %>
    <%= person_f.label :id %>
    <%= person_f.text_field :id %>
  <% end %>
</li>

это кстати, тоже не работает.когда я нажимаю «отправить», ничего не происходит.ничего не будет сохранено или изменено или что-то еще.

Так что я подумал, просто ради эксперимента, скажу, что я использовал идентификаторы для идентификации модели Person (чтобы мне не приходилось выполнять автозаполнение со скрытым полем id, которым я являюсьиспользую для другого проекта. Я ненавижу это).Все, что я хочу, - это перейти на новую / отредактированную страницу компании, там есть куча текстовых полей, чтобы я мог ввести идентификаторы людей и сохранить их, а затем эти люди ассоциируются с компанией.Я имею в виду, это точно как

people = Person.find(1,2,3)
#=>["romeo","juliet","henry"]
company = Company.first
#=>["Shakespeare Co."]
company.people<<people
company.people
#=>["romeo","juliet","henry"]

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

Спасибо !!

1 Ответ

4 голосов
/ 23 января 2010

accepts_nested_attributes_for :people определяет методы people_attributes и people_attributes= в модели вашей компании. Эти два метода используются, когда у вас есть fields_for :people в форме. Как указано в документации (читать всю страницу, а не только определение метода):

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

Невозможно связать два объекта, что можно сделать без него, у вас все еще есть метод people в Компании.

Formtastic например использует select с несколькими атрибутами (вы можете проверить несколько опций с помощью ctrl) или список флажков (проще для обычного пользователя, не нужно прикасаться к клавиатуре).

Если вы хотите использовать автозаполнение, это может быть сделано, но вам нужно добавить свои идентификаторы в массив people[] (не помню формат сейчас, я проверю позже. Вы можете проверить его формат при создании атрибут в вашей форме для :people я думаю)

Edit:
Я думаю, я знаю, что делать это простым способом (без автозаполнения, только с простым html).

В вашем companies/edit (или new) месте просмотра:

<p>
  <%= company_f.label :people %>
  <%= company_f.collection_select :person_ids, Person.all, :id, :name, {}, {:multiple => true} %>
</p>

Это позволит вам выбрать несколько человек в компанию (с помощью Ctrl). Параметры, генерируемые этой частью, передаваемой вашему контроллеру, теперь должны выглядеть следующим образом:

"company"=>{"name"=>"CompanyA", "person_ids"=>["1", "3"]}, "commit"=>"Update", "id"=>"4"

Если вы хотите показать людям с флажками, мне удалось получить это с этим (я скопировал часть разметки из formtastic ):

<ul>
  <% Person.all.each do |person| %>
    <li>
      <%= check_box :person, :id, {:name => "company[person_ids][]", :checked => @company.people.include?(person) }, person.id, nil %>
      <%= person.name %>
    </li>
  <% end %>
</ul>

Сегодня у меня не было времени проверить, как это сделать со скрытыми полями, поэтому вы можете использовать автозаполнение, но я считаю, что оно должно быть похоже на флажки - вам нужно использовать что-то, что добавляет <input type="hidden" name="company[person_ids][]" value="#{person.id}"> для каждого автозаполненного человека, а также необходимо создать первоначальный список людей, уже работающих в компании ( ВЫ ПЕРЕПИСЫВАЕТЕ В СПИСОК , а не в список).


Если вы хотите, чтобы поле добавляло или удаляло (отдельные поля, извините) людей из компании, то это должно работать:

в модели фирмы:

def add_people=(people_ids)
  ids = people_ids.split(/,/).map(&:to_i)
  person_ids += ids if ids
end
def add_people
  ""
end
def remove_people=(people_ids)
  ids = people_ids.split(/,/).map(&:to_i)
  person_ids -= ids if ids
end
def remove_people
  ""
end

и в вашем новом / редактируемом представлении:

<p>
  <%= f.label :add_people %><br />
  <%= f.text_field :add_people %>
</p>
<p>
  <%= f.label :remove_people %><br />
  <%= f.text_field :remove_people %>
</p> 

Теперь все, что вам нужно сделать, это найти JavaScript для автозаполнения, подключить его к идентификаторам и именам всех людей (вероятно, PeopleController#index, :format => :json должно быть хорошо) и сказать ему заполнить эти поля text_fields (могут быть скрытые поля, если вы будет использовать автозаполнение).

Этот подход должен работать, поскольку вы определяете виртуальные атрибуты в модели компании, и, присваивая им строку в формате "1, 2, 6", вы добавляете / удаляете эти идентификаторы из своей коллекции связанных людей

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...