Reputation: 751
I am trying to make a simple blog app with rails as part of an exercise. Right now, you have the ability to add a comment on the post_path directly on show page of a post.
I'd like to be able to save a Comment object and have it be nested under a Post object so they are related.
My form looks like this:
#_form.html.erb
<%= form_for @comment, :url => post_comments_path(@post) do |f| %>
<%= f.label :content %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
I click submit and I am transported to the comments controller:
#comments_controller.rb
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.new
@comment.save(comment_params) # @comment is saved but :content is nil
if @comment.save(comment_params)
redirect_to post_path(@post)
end
end
if I look at comment_params
inside the create action I see:
=> {"content"=>"asdfasdfasdfasdf"}
. The comment gets saved, however the :content portion is empty as you can see below:
=> #<Comment:0x007fd1da63ce60
id: 4,
content: nil,
post_id: "1",
created_at: Mon, 26 Oct 2015 21:45:22 UTC +00:00,
updated_at: Mon, 26 Oct 2015 21:45:22 UTC +00:00,
user_id: nil>
I do have :content
white listed in my strong params:
def comment_params
params.require(:comment).permit(:content, :post_id)
end
Here are my models..
#post.rb
class Post < ActiveRecord::Base
has_and_belongs_to_many :tags
has_many :comments
belongs_to :user
validates :title, :presence => true
validates :body, :presence => true
###methods###
def all_tags=(names)
self.tags = names.split(",").map do |name|
Tag.where(name: name.strip).first_or_create!
end
end
def all_tags
self.tags.map(&:name).join(", ")
end
end
#comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
end
and my schema.
# schema..
create_table "comments", force: :cascade do |t|
t.string "content"
t.string "post_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "posts_tags", force: :cascade do |t|
t.integer "post_id"
t.integer "tag_id"
end
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "username"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
Upvotes: 3
Views: 67
Reputation: 802
Try changing to:
#comments_controller.rb
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.new(comment_params)
if @comment.save
redirect_to post_path(@post)
end
end
Update with explanation:
old:
# creates empty comment that belongs to @post
@comment = @post.comments.new
new:
#creates a comment that belongs to @post and has the content of comment_params
@comment = @post.comments.new(comment_params)
old:
@comment.save(comment_params)
if @comment.save(comment_params)
redirect_to post_path(@post)
end
# is the same as @comment.save({}) as far as save is concerned.
# save takes a hash for options. It only uses the options it knows
# So that is why it didn't complain. It didn't find anything it knew
# in the hash comment_params. So it just saved the empty comment
new:
if @comment.save # save the new comment that was generated with comment_params
redirect_to post_path(@post)
end
Upvotes: 2