Rails 3.1: accepts_nested_attributes_for и ассоциация has_one — не будет работать?

#ruby-on-rails #ruby-on-rails-3.1

#ruby-on-rails #ruby-on-rails-3.1

Вопрос:

Я пытаюсь использовать accepts_nested_attributes_for в модели ассоциации has_one и не получаю абсолютно ничего:-(

У меня есть две модели: пользователь и местоположение. У пользователя есть одно местоположение:

 class User < ActiveRecord::Base
  # current location
  has_one :location, :dependent => :destroy
  accepts_nested_attributes_for :location
end

class Location < ActiveRecord::Base
  belongs_to :user
end
  

Я могу сохранить изменения в модели с помощью User.find(1).location.current_location_text = "blah" консоли, поэтому я знаю, что ассоциации настроены правильно.

У меня есть две формы на странице редактирования пользователя. Тот, который обновляет основные атрибуты пользователя (и работает нормально и не показан ниже), а затем этот, который позволяет пользователю обновлять атрибут модели местоположения, называемый «current_location_text»:

 <%= form_for(@user) do |f| %>  
    <%= fields_for(@user.location) do |location_fields| %>
        <%= location_fields.label :current_location_text, 'Current Location' %>
        <%= location_fields.text_field :current_location_text, :placeholder => 'Road, City or Postcode' %>
    <% end %>

    <%= f.submit "Update Current Location" %>
<% end %>
  

Это не работает. Я немного смущен, поскольку параметры, отправленные формой, выглядят неверно. Когда форма отправлена, это отображается в журнале:

 Started PUT "/users/1" for 127.0.0.1 at 2011-10-08 00:28:05  0100
  Processing by UsersController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"YdTAsXwEvRgXIqri jfx3dLlYG2XWQTuYkgLDsO/OJw=", "location"=>{"current_location_text"=>"E14 8JS"}, "commit"=>"Update Current Location", "id"=>"1"}
  User Load (10.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  User Load (5.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = ? LIMIT 1  [["id", "1"]]
  SQL (4.4ms)  BEGIN
   (2.5ms)  COMMIT
Redirected to http://localhost:3000/users/1
  

Две вещи, которые я нахожу странными в этом:

  1. Появляется сообщение «COMMIT», но без предшествующей строки обновления и без ошибки. например, если вы попытаетесь зафиксировать защищенный атрибут, в этот момент вы получите сообщение об ошибке «вы не можете массово назначить …».

  2. Параметры выглядят для меня неправильно. Бит «location» вложен, как я и ожидал, но я бы также ожидал, что это будет вложенный в «пользовательский» хэш, что-то вроде этого:

      {"utf8"=>"✓", "authenticity_token"=>"YdTAsXwEvRgXIqri jfx3dLlYG2XWQTuYkgLDsO/OJw=", "user"=>{"location"=>{"current_location_text"=>"E14 8JS"}, "commit"=>"Update Current Location", "id"=>"1"}}
      

Я не думаю, что я здесь совсем глуп. Я упускаю что-то действительно очевидное? Я попытался добавить дополнительные скрытые поля в свою форму, то есть идентификатор пользователя, а затем я получаю хэш пользователя, но на том же уровне, что и хэш «местоположения», а не как родительский элемент, как я ожидал!

Также, если это поможет, вот мое обновление в моем пользовательском контроллере:

def update @user = User.find(параметры [:id])

 if @user.update_attributes(params[:user])
  redirect_to current_user, :notice => 'User was successfully updated.'
else
  render :action => "edit"
end
  

конец

и вот что есть в моем routes.rb (хотя я не думаю, что это актуально):

 resources :users do
  resource :location
end
  

Любая помощь приветствуется. Если я не решу эту проблему, ноутбук выйдет из окна….
Спасибо.

Ответ №1:

 <%= fields_for(@user.location) do |location_fields| %>
  

Это ваша проблема. Вам нужно фактически «вложить» fields_for в вашу форму, например:

 <% f.fields_for(@user.location) do |location_fields| -%>
  

Комментарии:

1. Ссылка на документацию? Все, что я вижу в документах, это то, что <% -%> нужно иметь дело с конечными пробелами. ( api.rubyonrails.org/classes/ActionView/Base.html )

2. Просто чтобы уточнить, проблема была fields_for в vs f.fields_for . Это -%> была просто привычка.

Ответ №2:

Попробуйте это вместо

 <%= f.fields_for :location do |location_fields| %>
  

Вместо того, чтобы предоставлять ему сам объект, сообщите rails, для какой ассоциации вы хотите его загрузить

Комментарии:

1. Спасибо — мне действительно тоже нужно было это сделать, я нахожу странным, что использование объекта в объявлении fields_for не работает.

2. Для всех, кто использует Judge gem для встроенной проверки: вы получите ошибки с этим методом. Используйте @user.location вместо символа, потому что судья должен ссылаться на объект.