Не удается получить вложенную форму с ассоциацией has_one для работы - PullRequest
4 голосов
/ 07 апреля 2011

У меня есть следующие модели:

class User < ActiveRecord::Base
    has_one :city
    accepts_nested_attributes_for :city
end

class City < ActiveRecord::Base
    belongs_to :user
end

Это действие контроллера:

   def create
    @user = User.new(params[:user])

    respond_to do |format|
      if @user.save
        format.html { redirect_to(@user, :notice => 'User was successfully created.') }
        format.xml  { render :xml => @user, :status => :created, :location => @user }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
      end
    end
  end

и это представление:

<%= form_for :user,:url => users_path,:method => :post do |f| %>
<%= f.fields_for :city do |b| %>
    <%= b.collection_select :id,City.all,:id,:name %>
  <% end %>

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

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

<select name="user[city][id]" id="user_city_id">
   <option value="1">One</option>
   <option value="2">Two</option>
</select>

Обратите внимание, что его имя нигде не имеет attribute.Итак, когда я пытаюсь сохранить его, я получаю эту ошибку:

City(#37815120) expected, got ActiveSupport::HashWithIndifferentAccess(#32969916)

Как я могу это исправить?

РЕДАКТИРОВАТЬ: есть некоторый прогресс, я попытался изменить fields_for на это:

<%= f.fields_for :city_attributes do |b| %>
    <%= b.collection_select :id,City.all,:id,:name %>
<% end %>

и теперь, кажется, HTML генерируется правильно.Но теперь я получаю эту ошибку:

Couldn't find City with ID=1 for User with ID=

Я понятия не имею, что делать дальше.

EDIT2: кажется, что переопределение метода city_attributes= работает:

def city_attributes=(attribs)
    self.city = City.find(attribs[:id])
end

Я не знаю, так ли это, но кажется, что это хорошо.

Ответы [ 3 ]

2 голосов
/ 07 апреля 2011

Посмотрите на этот вопрос, который кажется похожим на ваш: Rails 3: Как работает "accepts_nested_attributes_for"?

На самом деле, поскольку города уже существуют, я думаю, что нетздесь нужны вложенные формы.

Попробуйте заменить

<%= f.fields_for :city_attributes do |b| %>
    <%= b.collection_select :id,City.all,:id,:name %>
<% end %>

на

<%= f.collection_select :city, City.all,:id,:name %>

Обновлено после комментариев

Не могли бы выизмените ваши отношения с (и обновите схему базы данных соответственно)

class User < ActiveRecord::Base
    belongs_to :city
end

class City < ActiveRecord::Base
    has_many :users
end

А затем попробуйте использовать:

<%= f.collection_select :city_id, City.all,:id,:name %>
1 голос
/ 19 февраля 2013

Вы также можете сделать

<%= f.collection_select :city_id, City.all, :id, :name %>

в своем представлении, а затем добавить виртуальные атрибуты в свою модель пользователя:

class User < ActiveRecord::Base
  ...
  def city_id(c_id)
    update_attribute(:city, City.find(c_id))
  end

  def city_id
    city.id
  end
end

Это может быть не оченьчистый, поскольку связанная модель города «сохраняется» при назначении идентификатора some_user.city_id.Тем не менее, это решение сохраняет ваш контроллер и обеспечивает хороший и чистый вид.

Примечание. Возможно, вы также захотите учесть пустой идентификатор, передаваемый методу установки.

0 голосов
/ 07 апреля 2011

Попробуйте это

<% = f.select (: city_id, City.all.collect {| p | [p.name, p.id]})%>

...