I'm trying to make a comment form on my Collection show page. I'm a bit rusty with Rails and I'm not sure why this form isn't attempting to Create a comment and is instead returning the error
The action 'update' could not be found for CommentsController
The comments system works in console.
Here is my form
<%= form_for [#commentable, #comment] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_area :content %>
<%= f.submit "Comment", class: "btn btn-large btn" %>
<% end %>
My comment model
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
belongs_to :user
end
My collection model
class Collection < ActiveRecord::Base
has_many :comments, as: :commentable
end
My comments_controller
class CommentsController < ApplicationController
def create
#comment = #commentable.comments.new(comment_params)
if #comment.save
flash[:success] = 'Comment posted!'
redirect_to #commentable
else
flash[:notice] = "Error creating comment: #{#comment.errors}"
redirect_to #commentable
end
end
private
def comment_params
params.require(:comment).permit(:content, :commentable_type, :commentable_id, :user_id)
end
end
My collections_controller show action
def show
#collection = Collection.find(params[:id])
#commentable = #collection
#comments = #commentable.comments
#comment = Comment.new if user_signed_in?
end
You're not using #commentable in your form or controller, which may be causing your problem:
<%= form_for [#commentable, #comment] do |f| %>
And your controller action should look like this:
def create
#comment = #commentable.comments.new(comment_params)
Update: Then to load commentable based on resource:
before_filter: load_commentable
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
Method courtesy Ryan Bates: http://railscasts.com/episodes/154-polymorphic-association-revised
Can you show the controller action that renders that forms? I think the problem is that #comment is already persisted/created so it tries to update it.
UPDATE:
I just noticed your show action. Yes the problem is that #comment is already persisted. Just change it to:
#comment = Comment.new if user_signed_in?
Related
I'm trying to create a comment on a video show page. When I submit the form, rails gives me a flash notice: "User must exist, Video must exist". Not sure why my strong params aren't going through to the create method.
comments_controller.rb
def create
#user = current_user
#video = Video.find(params[:video_id])
#comment = Comment.new(comment_params)
#post = #video.post
if #comment.save
flash[:notice] = "Comment successfully created"
redirect_to post_video_path(#post, #video)
else
#errors = #comment.errors.full_messages.join(', ')
flash[:notice] = #errors
render :'videos/show'
end
private
def comment_params
params.require(:comment).permit(
:body,
:user,
:video
)
end
models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :video
validates :body, presence: true
end
models/video.rb
class Video < ActiveRecord::Base
belongs_to :user
belongs_to :post
has_many :comments
end
views/videos/show.html.erb
<%= #video.title %>
<%= content_tag(:iframe, nil, src: "//www.youtube.com/embed/#{#video.embed_id}") %>
<%= link_to "Delete Video", post_video_path(#post, #video), method: :delete %>
<%= link_to('Back', user_post_path(#user, #post)) %>
<h3>Comments</h3>
<%= form_for [#video, #comment] do |f| %>
<%= f.label(:body, "Comment") %>
<%= f.text_area(:body) %>
<%= f.submit("Submit Comment") %>
<% end %>
<% unless #comments.nil? %>
<% #comments.each do |comment| %>
<%= comment.body %>
<%= comment.user %>
<% end %>
<% end %>
I tried adding this to the create method...
#comment.user = current_user
#comment.video = #video
That allowed the comment to save but instead of displaying the comment.body, it displayed the comment object. It still doesn't explain why the strong params aren't being passed.
This is probably a nested params issue and how you have the strong params defined. Check this answer for more information.
If you need to see what is in the params, insert a pry statement into the controller and inspect it there.
Good luck!
There are multiple things you should look at. I have made multiple changes to your code. Go through them.
In your videos/show.html.erb
<%= form_for Comment.new do |f| %>
<%= f.label(:body, "Comment") %>
<%= f.text_area(:body) %>
<%= f.hidden_field :video_id, :value => #video.id %>
<%= f.submit("Submit Comment") %>
<% end %>
Send video_id using hidden_field. Do not send current user id for security reasons. If you take current user id from form end user can easily edit your form in html and pass someone else's user id and this will be one of the easiest and major vulnerability.
In comments_controller.rb
def create
#comment = Comment.new(comment_params)
#comment.user = current_user # we are making sure that current_user is set to comment.
if #comment.save
flash[:notice] = "Comment successfully created"
redirect_to post_video_path(#comment.video.post, #comment.video)
else
#errors = #comment.errors.full_messages.join(', ')
flash[:notice] = #errors
render :'videos/show'
end
end
private
def comment_params
params.require(:comment).permit(:body, :user, :video_id)
# We are permitting video_id instead of video
end
I got this to work but I'm not sure if this addresses the security concerns that #Dinesh raised.
comments_controller.rb
def create
#user = current_user
#video = Video.find(params[:video_id])
#comment = Comment.new(comment_params)
#comment.user = #user
#comment.video = #video
#post = #video.post
if current_user == #video.user || current_user.admin
if #comment.save
flash[:notice] = "Comment successfully created"
redirect_to post_video_path(#post, #video)
else
#errors = #comment.errors.full_messages.join(", ")
flash[:notice] = #errors
render :"videos/show"
end
else
flash[:notice] = "Only OP or admin may comment"
render :"videos/show"
end
end
and
private
def comment_params
params.require(:comment).permit(
:body,
)
end
The problem is in replying, each time i submit a reply it a new reply and comment is created.
Here's my comments controller
def new
#comment = Comment.new
end
def create
#post = Post.find(params[:post_id])
if params[:parent_id].present?
#comment = Comment.find(params[:parent_id]).replies.new.(comment_params)
elsif params[:parent_id].blank?
#comment = #post.comments.new(comment_params)
#comment.user = current_user
end
if #comment.save
flash[:success] = 'Your comment was successfully added!'
redirect_to :back
else
render 'new'
end
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
if #comment.destroy
redirect_to :back
end
end
private
def comment_params
params.require(:comment).permit(:body, :parent_id)
end
end
and
and in my _comment.html.erb
<%= render comment.replies if comment.replies.any? %>
<%= form_for [comment.post, comment.replies.new] do |f| %>
<%= f.hidden_field :parent_id, :value => comment.id %>
<%= f.text_field :body %>
<%= f.submit 'reply', name: 'reply' %>
<% end %>
in my model
belongs_to :parent, class_name: "Comment"
has_many :replies, class_name: "Comment", foreign_key: :parent_id, dependent: :destroy
When the reply is submitted the a params[:parent_id] is passed.
The problem
If-Else statement is not working, I need it to know if a comment or a reply is submitted.
If it did work I don't know how to get the comment I'm creating the reply in.
Hope everything is clear, thanks.
Based on your form parent_id is coming under comment params, so it should be something like this
#post = Post.find(params[:post_id])
if params[:comment][:parent_id].present?
#comment = Comment.find(params[:parent_id]).replies.new.(comment_params)
elsif params[:comment][:parent_id].blank?
#comment = #post.comments.new(comment_params)
#comment.user = current_user
end
Hope it helps!
How can I show all comments in the post#show?
comments_controller
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#comment = Comment.new(comment_params)
#post = Post.find(params[:post_id])
#comment.user_id = current_user.id
#comment.username = current_user.username
#comment.post_id=#post.id
#comment.save
redirect_to post_path(#post)
end
def show
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:text, :username)
end
end
Models:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
#app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
end
#app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
the views/posts/show.html.erb
<ul class="img-list-single">
<li>
<a>
<img src=<%= #post.url %>/>
<span class="text-content"><span><%=#post.title%></span></span>
</a>
<%= #comment.username%>
<%if current_user%>
<%= form_for :comment, :url => post_comments_path(#post) do |f|%>
<%= f.text_field :text %>
<%= f.submit%>
<% end %>
<%if current_user.id==#post.user_id%>
<%= button_to 'Delete', #post, method: :delete, :onclick => " returconfirm('Are you sure you want to delete this post?')"%>
<%end%>
<%end%>
First of all fix your posts controller. The show action should look like this:
class PostsController < ApplicationController
def show
#post = Post.find(params[:id])
#comments = #post.comments.includes(:user)
end
end
Now in app/views/posts/show.html.erb, I would render a partial:
<ul>
<%= render #comments %>
</ul>
Rails will look for a partial in app/views/comments/_comment.html.erb. You can just put all your comment view logic in there and will display all the comments:
# app/views/comments/_comment.html.erb
<li>
<%= comment.text %>
<br>
<%= comment.user.try(:username) %>
</li>
Finally, I would fix your create action in the comments controller:
class CommentsController < ApplicationController
def create
# First get the parent post:
#post = Post.find(params[:post_id])
# Then build the associated model through the parent (this will give it the correct post_id)
#comment = #post.comments.build(comment_params)
# Assign the user directly
#comment.user = current_user
if #comment.save
redirect_to post_path(#post)
else
render :new
end
end
end
It seems to me that you don't need to store the username attribute on the comment model, since that should be available through the comment.user association.
in your post#show action simply do:
#post = Post.find(params[:id])
#comments = #post.comments
then in your view add:
<% #comments.each do |comment| %>
<%= comment.text %>
<br />
<% end %>
I want to create a comments controller.But when rails render form, browser show an error 'First argument in form cannot contain nil or be empty', though the variable is defined.
there is comments_controller
class CommentsController < ApplicationController
def new
end
def create
#comment = current_user.comments.build(comment_params)
if #comment.save
redirect_to root_url
else
render 'static_pages/home'
end
end
private
def comment_params
params.require(:comment).permit(:text)
end
end
new.html.erb
<%= form_for(#comment) do |f| %>
<%= f.text_field :text %><br><br>
<% end %>
how fix?
sorry for my bad English
Fix :-
class CommentsController < ApplicationController
def new
#comment = Comment.new
end
# ....
end
I'm working on an app that allows users to comment on a single "work" (think blog post). The associations in the models are as follows:
class User < ActiveRecord::Base
has_many :works
has_many :comments
class Work < ActiveRecord::Base
belongs_to :user
has_many :comments
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
belongs_to :work
In the comments table, a record has the following fields:
id
content
user_id
created_at
updated_at
work_id
In my Comments controller, I have the following Create action:
def create
#work = Work.find(params[:id])
#comment = #work.comments.create(params[:comment])
#comment.user = current_user
if #comment.save
#flash[:success] = "Post created!"
redirect_to root_url
else
render 'activities'
end
end
I'm trying to associate both the user AND the work to the comment but I get the following error message when I try to create a comment:
Unknown action
The action 'update' could not be found for CommentsController
I'm trying to use the following StackOverflow answer as a guide but the solution is not working for me:
Multiple Foreign Keys for a Single Record in Rails 3?
EDIT:
I have a add comment form on the works#show action:
def show
#work = Work.find(params[:id])
#comment = current_user.comments.create(params[:comment])
#activities = PublicActivity::Activity.order("created_at DESC").where(trackable_type: "Work", trackable_id: #work).all
#comments = #work.comments.order("created_at DESC").where(work_id: #work ).all
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #work }
end
end
The Comment form itself:
<%= form_for(#comment) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Post a comment!" %>
</div>
<%= f.submit "Post", class: "btn btn-small btn-primary" %>
<% end %>
I also have an update method on the Comments controller:
def update
#comment = current_user.comments.find(params[:id])
if #comment.update_attributes(params[:comment])
flash[:success] = "Comment updated"
redirect_to #comment
end
end
The error message says:
The action 'update' could not be found for CommentsController
So, the issue is that your form is trying to call an update action on the CommentsController. This is unrelated to adding both the User and the Work instance as foreign keys. Your code for that seems right.
For sure if you persist the comment to the database during the show action:
#comment = current_user.comments.create(params[:comment])
Then the form helper will build an update form rather than a create form (because the model already exists):
<%= form_for(#comment) do |f| %>
If the desired action is to POST a comment create from the show page then try building the comment in the show action:
#comment = current_user.comments.build(params[:comment])