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:
:category_attributes
in the post_params
strong parameter method?Category
attributes
are nested inside the Post
parameter?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?build_category
method and I will need to add this to the create
action?Category
model (presence: true
) be
automatically used on the Post
form?Thanks in advance.
category_fields
inside fields_for
block.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.
@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])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With