[ActiveRecord::RecordInvalid - Validation failed: Blog must exist]
Hi,
trying to sort out this error for a while now, no luck.
I get this error above when adding a new comment for a blogpost. The blog is clearly there. Any insight would be much appreciated.
_comment.html.erb
<div class="comment-card">
<div class="card">
<div class="card-block">
<div class="row">
<div class="col-md-1">
</div>
<div class="col-md-11">
<%= comment.content %>
</div>
</div>
</div>
</div>
</div>
_comment_form.html.erb
<% unless current_user.is_a? GuestUser %>
<%= form_for @comment, url: '#' do |f| %>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: 'form-control' %>
</div>
<%= f.submit 'Post Comment', class: 'btn btn-primary' %>
<% end %>
<% end %>
comment.rb
class Comment < ApplicationRecord
belongs_to :user
belongs_to :blog
validates :content, presence: true, length: { minimum: 5, maximimum: 1000 }
after_create_commit { CommentBroadcastJob.perform_later(self) }
end
comment_controller.rb
class CommentsController < ApplicationController
def create
@comment = current_user.comments.build(comment_params)
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
blogs_controller.rb
def show
@blog = Blog.includes(:comments).friendly.find(params[:id])
@comment = Comment.new
@page_title = @blog.title
@seo_keywords = @blog.body
end
Terminal output:
Could not execute command from ({"command"=>"message", "identifier"=>"{\"channel\":\"BlogsChannel\",\"blog_id\":\"\"}", "data"=>"{\"comment\":\"sdgergre\",\"blog_id\":\"\",\"action\":\"send_comment\"}"}) [ActiveRecord::RecordInvalid - Validation failed: Blog must exist]:
Thanks Jack,
blog_id
is being added actually
blogs_channel.rb
class BlogsChannel < ApplicationCable::Channel
def subscribed
stream_from "blogs_#{params['blog_id']}_channel"
end
def unsubscribed
end
def send_comment(data)
current_user.comments.create!(content: data['comment'], blog_id: data['blog_id'])
end
end
blogs_controller.rb
def show
@blog = Blog.includes(:comments).friendly.find(params[:id])
@comment = Comment.new
end
show.html.erb
<div class="col-sm-8 blog-main">
<h2> <%= @blog.title %></h2>
<%= link_to 'Edit', edit_blog_path(@blog) if logged_in?(:site_admin) %>
<p><%= @blog.body %></p>
<%= render 'comments/comment_form' %>
<div id="comments" data-blog-id="<%= @blog_id %>">
<%= render @blog.comments %>
</div>
</div>
I can create the comment in terminal:
[2] pry(main)> Comment.create!(user_id: User.last.id, blog_id: Blog.last.id, content: "1234567")
User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
Blog Load (0.2ms) SELECT "blogs".* FROM "blogs" ORDER BY "blogs"."id" DESC LIMIT $1 [["LIMIT", 1]]
(0.1ms) BEGIN
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Blog Load (0.1ms) SELECT "blogs".* FROM "blogs" WHERE "blogs"."id" = $1 LIMIT $2 [["id", 20], ["LIMIT", 1]]
SQL (54.8ms) INSERT INTO "comments" ("content", "user_id", "blog_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["content", "1234567"], ["user_id", 1], ["blog_id", 20], ["created_at", "2018-02-02 05:45:37.058157"], ["updated_at", "2018-02-02 05:45:37.058157"]]
(9.1ms) COMMIT
Enqueued CommentBroadcastJob (Job ID: 22604b93-a864-4213-a348-0e0da6c69ee0) to Async(default) with arguments: #<GlobalID:0x007f93f1e3cfb0 @uri=#<URI::GID gid://web-portfolio/Comment/7>>
=> #<Comment:0x007f93f52996f0
id: 7,
content: "1234567",
user_id: 1,
blog_id: 20,
created_at: Fri, 02 Feb 2018 05:45:37 UTC +00:00,
updated_at: Fri, 02 Feb 2018 05:45:37 UTC +00:00>
[3] pry(main)> Comment Load (0.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."id" = $1 LIMIT $2 [["id", 7], ["LIMIT", 1]]
Performing CommentBroadcastJob (Job ID: 22604b93-a864-4213-a348-0e0da6c69ee0) from Async(default) with arguments: #<GlobalID:0x007f93f0fd68b8 @uri=#<URI::GID gid://web-portfolio/Comment/7>>
Blog Load (0.3ms) SELECT "blogs".* FROM "blogs" WHERE "blogs"."id" = $1 LIMIT $2 [["id", 20], ["LIMIT", 1]]
Rendered comments/_comment.html.erb (1.7ms)
[ActionCable] Broadcasting to blogs_20_channel: {:comment=>"\t<div class=\"comment-card\">\n\t\t<div class=\"card\">\n\t\t\t<div class=\"card-block\">\n\t\t\t\t<div class=\"row\">\n\t\t\t\t\t<div class=\"col-md-1\">\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"col-md-11\">\n\t\t\t\t\t\t1234567\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>"}
Performed CommentBroadcastJob (Job ID: 22604b93-a864-4213-a348-0e0da6c69ee0) from Async(default) in 424.54ms
Hi Linards,
I think what Jack is referring to is your comments controller create action:
class CommentsController < ApplicationController
def create
@comment = current_user.comments.build(comment_params)
end
private
def comment_params
params.require(:comment).permit(:content) #you're only allowing :content
end
end
Your comment params are only permitting :content
and in your new comment form you don't pass the blog ID either:
<% unless current_user.is_a? GuestUser %>
<%= form_for @comment, url: '#' do |f| %>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: 'form-control' %>
</div>
<%= f.submit 'Post Comment', class: 'btn btn-primary' %>
<% end %>
<% end %>
And in your show action you're just creating a new comment without associating the @blog.id
:
def show
@blog = Blog.includes(:comments).friendly.find(params[:id])
@comment = Comment.new # you should be building the comment from the blog
end
So what you should be able to do is something like:
def show
@blog = Blog.includes(:comments).friendly.find(params[:id])
@comment = @blog.comments.build
end
Which should now properly pass the :blog_id
. You may have to play with this some, I haven't tested and I've only had one cup of coffee so my brains not firing on all cylinders yet but this should get you going in the right direction.
You could also do something like this (but the above is the more railsy way)
<% unless current_user.is_a? GuestUser %>
<%= form_for @comment, url: '#' do |f| %>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: 'form-control' %>
<%= f.hidden_field :blog_id, @blog.id %>
</div>
<%= f.submit 'Post Comment', class: 'btn btn-primary' %>
<% end %>
<% end %>
And then just add to your permitted params:
class CommentsController < ApplicationController
def create
@comment = current_user.comments.build(comment_params)
end
private
def comment_params
params.require(:comment).permit(:content, :blog_id)
end
end
The ActiveRecord::RecordInvalid error usually occurs when there is a data validation error during storage into the database using ActiveRecord in Ruby on Rails. To fix this error, you need to recheck your code to identify the error and fix it.