Подтвердить что ты не робот

Rails 4 has_one форма ассоциации не создается

Мне нужны некоторые указатели на то, как Rails 4 работает с ассоциацией has_one и belongs_to.

Моя форма не сохраняет отношения has_one

Модель публикации

class Post < ActiveRecord::Base
  validates: :body, presence: true

  has_one :category, dependent: :destroy
  accepts_nested_attributes_for :category
end

class Category < ActiveRecord::Base
  validates :title, presence: true
  belongs_to :post
end

Почтовый контроллер

class PostController < ApplicationController
  def new
    @post = Post.new
    @post.build_category
  end

  def create
    @post = Post.new(post_params)
  end

  private

  def post_params
    params.require(:post).permit(:body)
  end
end

Форма в посту # новое действие

<%= form_for @post do |form| %>

  <%= form.label :body %>
  <%= form.text_area :body %>

  <%= fields_for :category do |category_fields| %>
    <%= category_fields.label :title %>
    <%= category_fields.text_field :title %>
  <% end %>

  <%= form.button "Add Post" %>

<% end %>

Он не сохраняет заголовок category при отправке формы Post.

Параметры отладки

utf8: ✓
authenticity_token: 08/I6MsYjNUhzg4W+9SWuvXbSdN7WX2x6l2TmNwRl40=
post: !ruby/hash:ActionController::Parameters
  body: 'The best ice cream sandwich ever'
category: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  title: 'Cold Treats'
button: ''
action: create
controller: posts

Журнал приложений

Processing by BusinessesController#create as HTML
  Parameters: {"utf8"=>"✓",
               "authenticity_token"=>"08/I6MsYjNUhzg4W+9SWuvXbSdN7WX2x6l2TmNwRl40=",
               "post"=>{"body"=>"The best ice cream sandwich ever"},
               "category"=>{"title"=>"Cold Treats", "button"=>""}

В консоли Rails.. Я могу выполнить следующее успешно

> a = Post.new
=> #<Post id: nil, body: "">
> a.category
=> nil

> b = Post.new
=> #<Post id: nil, body: "">
> b.build_category
=> #<Post id: nil, title: nil>
> b.body = "The best ice cream sandwich ever"
=> "The best ice cream sandwich ever"
> b.category.title = "Cold Treats"
=> "Cold Treats"

Вопросы, которые у меня есть, касаются того, как решить эту проблему:

  • Я не уверен, что мне нужно добавить :category_attributes в сильном параметре post_params?
  • Если параметры журналов и отладки показывают, что атрибуты category вложены внутри параметра Post?
  • В хэш-параметре category имеется пустой ключ button, который не находится в моем fields_for. Я что-то упускаю при использовании помощников формы?
  • Является причиной, потому что действие create не принимает build_category, и мне нужно будет добавить это к созданию действие?
  • Будут ли проверки на модели category (presence: true) автоматически используется в форме Post?

Спасибо заранее.

Обновление: отсутствует category_fields внутри fields_for.

4b9b3361

Ответ 1

Вопрос №1: Да, вам нужно добавить :category_attributes в сильном параметре post_params, например:

def post_params
  params.require(:post).permit(:body, category_attributes: [:title])
end

Вопрос № 2: Да, параметры должны быть вложенными, это опечатка в вашем представлении, потому что вы не применяете fields_for (множественное число кстати) в области родительского form builder, также вы не используете построитель форм category_fields внутри блока fields_for!

Вид должен выглядеть так:

<%= form_for @post do |form| %>

  <%= form.label :body %>
  <%= form.text_area :body %>

  <%= form.fields_for :category do |category_fields| %>
    <%= category_fields.label :title %>
    <%= category_fields.text_field :title %>
  <% end %>

  <%= form.button "Add Post" %>

<% end %>

Вопрос № 3: Параметр кнопки может быть не в том месте, из-за смешения формы в вашем представлении.

Вопрос № 4: Вам не нужно создавать дочернюю модель в действии create, если вы принимаете вложенные атрибуты

Вопрос № 5: Да, проверка дочерней модели также выполняется, и если проверка дочернего элемента не выполняется, родитель также будет иметь ошибку и не будет сохранен в базе данных.

Ответ 2

@sled, вы правы. Но для будущих Rails 4.1 bolded (**) будет устаревшим

def post_params
  params.require(:post).permit **(:body, :category_attributes => [:title])**
end

bolded будет вынужден быть таким (: body, category_attributes: [: title])