Rails 4 has_one association form not building

12,161

Solution 1

Question #1: Yes, you need to add the :category_attributes in the post_params strong parameter method like this:

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

Question #2: Yes, the parameters should be nested, this is a typo in your view because you are not applying the fields_for (plural by the way) in the scope of the parent form builder, also you are not using the category_fields form builder inside the fields_for block!

The view should look like this:

<%= 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 %>

Question #3: The button parameter might be in the wrong place due to the mixed up form building in your view.

Question #4: You don't need to build the child model in your create action if you accept nested attributes

Question #5: Yes, the validation of the child model is also run and if the validation of the child fails, the parent will also have an error and is not saved to the database.

Solution 2

@sled you are right. But for future Rails 4.1 bolded (**) will be deprecated

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

bolded will be forced to be so (:body, category_attributes: [:title])

Share:
12,161

Related videos on Youtube

Wasabi Developer
Author by

Wasabi Developer

Updated on June 04, 2022

Comments

  • Wasabi Developer
    Wasabi Developer almost 2 years

    I need some pointers on how Rails 4 works with has_one and belongs_to association.

    My form doesn't save the has_one relationship

    Post Model

    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
    

    Post Controller

    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 in the Post#new action

    <%= 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 %>
    

    It's not saving the category title when the Post form is submitted.

    Debug params

    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
    

    App log

    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"=>""}
    

    In the Rails console.. I can run the following succesfully

    > 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"
    

    The questions I have the relates to how to tackle this problem:

    1. I'm not sure if I have to add :category_attributes in the post_params strong parameter method?
    2. Should the logs and debug params show that the Category attributes are nested inside the Post parameter?
    3. In the Category hash parameter there is a blank button key that isn't in my fields_for am I missing something when using the form helpers?
    4. Is the reason because the create action doesn't take the build_category method and I will need to add this to the create action?
    5. Will validations on the Category model (presence: true) be automatically used on the Post form?

    Thanks in advance.

    Update: missing category_fields inside fields_for block.

  • Wasabi Developer
    Wasabi Developer over 10 years
    Sled, you sir are a gentleman. Thank you for pointing out my wrong ways. I have been looking at the same form for days not know that I needed to add form.builder inside the fields_for block. Thanks again for clarifying the strong parameter nested attributes. I really appreciate the time you took to answer all my questions. Thank you! :)