Add Comment to User and Post models (Ruby on Rails)
In your way you should put this:
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.create(comment_params)
@comment.user_id = current_user.id #or whatever is you session name
if @comment.save
redirect_to @post
else
flash.now[:danger] = "error"
end
end
And also you should remove user_id from comment_params as strong parameters .
Hope this will help you .
Adding a comment model to associate with a post/user model
Your associations seem fine. The error
NoMethodError in Posts#show undefined method `comments_path'
means that you don't have the route comments_path
or Comments#Create
. Basically, when you have a form_for
with a Comment
as the parameter, it assumes you are wanting to go to the create
or update
route, depending if it's a new record. The easiest thing to do would be to add
resources :comments
to your routes file. However, since you want a comment associated with a post, you want to modify your routes file to have:
resources :posts do
resources :comments
end
Then, change your form to look like this:
<%= form_for [@post, @comment] do |f| %>
So when you submit a form, you will have a params[:post_id]
and a params[:id]
to play with. Find the Post
with the params[:post_id]
. Ignore the params[:id]
when you're creating a comment, but use it when you're updating a comment.
Edit: Here is a link to some help regarding Nested Resourcing.
Ruby on Rails blog and adding comments to posts and editing and deleting comments
The First argument in form cannot contain nil or be empty
is telling you that @comment
in <%= form_for @comment do |f| %>
is nil
. This is because in the edit
action of your CommentsController
you are setting @post
instead of @comment
.
Change this to be:
def edit
@comment = Comment.find(params[:id])
end
For deleting a comment, the Couldn't find Comment without an ID
is telling you that the value you're passing to find
is nil
. This is because you're trying to use params[:comment_id]
instead of params[:id]
. Change the destroy action to:
def destroy
@comment = Comment.find(params[:id])
@comment.destroy
redirect_to '/posts'
end
Update:
Also as per your code, you should change edit
and delete
links to below
<%= link_to("Edit Comment", edit_comment_path(c)) %>
<%= link_to("Delete Comment", comment_path(c), method: :delete)
You are passing @post.id
which is an id of post. Instead you should pass id of the comment using the block variable from your comments.each
, noticing that the .id
isn't needed here because it can be inferred by Rails.
How can I comments to my posts?
In your post controller show action, make the new comment belong to the post
def show
@post = Post.where(:id => params[:id]).first
if @post.nil?
flash[:error] = "Post does not exist"
redirect_to(root_path)
end
@comment = @post.comments.new # <--- here's the change
end
Then add the post_id field to the form as a hidden field
<%= form_for @comment do |f| %>
<%= f.hidden_field :post_id %>
<%= f.text_area(:content, :size => '20x10', :class => 'textarea') %>
<%= f.submit('Create Post', class: 'button button-primary') %>
<% end %>
And you should be good to go without changing the comment controller create action
Add Comment to User and Post models Rails 4
Short names are easier to read and understand so I will rename your models in my example to Artist
, Micropost
and Comment
class Artist < ActiveRecord::Base
has_many :microposts, dependent: :destroy
has_many :comments, through: :microposts, dependent: :destroy
end
class Micropost < ActiveRecord::Base
belongs_to :artist
has_many :comments, dependent: :destroy
end
class Comment < ActiveRecord::Base
# I renamed artist to commenter to make it clear that is not the same artist as the one that created the micropost,
# this implies that instead of author_id you will have commented_id in comments table
belongs_to :commenter, :class_name => Artist
belongs_to :micropost
end
### views/artists/show.html.erb ###
<% @artist.microposts.each do |micropost| %>
...
<%= micropost.content %>
...
<% micropost.comments.each do |comment| %>
# here you display comments for each micropost
<%= comment.content %>
# pay attention at the way I builded the comment
<%= form_for(micropost.comments.build) do |f| %>
<%= f.hidden_field :micropost_id %> # this will make the link to your micropost
<%= f.text_area :content %>
<%= f.submit "post comment" %>
<% end %>
<% end %>
<% end %>
In your comments_controller
you must assign current logged in artist (the commenter) to your comment.
class CommentsController < ApplicationController
def create
@comment = Comment.new(comment_params)
@comment.commenter = current_artist
if @comment.save
...
end
end
private
def comment_params
params.require(:comment).permit(:micropost_id, :content)
end
end
To avoid N+1 when you load artists, microposts and commenters do something like this:
class ArtistsController < ApplicationController
def show
@artist = Artist.includes(:microposts, :comments => :commenter).find(params[:id])
end
end
In 3-tiered relationship (User-Post-Comment), should user model include has_many :comments?
Edit:
Regarding these queries:
(1) query all other users' comments on this particular post for this particular user's comments.
And (2) query all the original user's comments on this particular post.
For (1), you will need to change the comments table to have a comment_id
, which is the comment its responding to.
Then you can have in comment.rb
: belongs_to :comment
.
To get all the comments on a given post for a given comment, you'll query like this:
Comment.where(comment: parent_comment, post: some_post) # parent_comment & post must be set somewhere
This should return all comments that are responding to parent_comment
for some_post
.
For (2), you will need to add a user_id
column to comments table, and add the following associations:
# comment.rb
belongs_to :user
# user.rb
has_many :comments
Then query the user's comments like this:some_user.comments.where(post: some_post) # some_user & some_post must be set beforehand
This will return all comments made by some_user
on some_post
.
Original answer:
If the comments
table does not have a user_id
column; then you cannot have it associated with a user with belongs_to :user
.
If you want a way to get all comments made by a user on any post, you can use has_many :comment, through: :posts
in the User
model. For example:
# user.rb
has_many :posts
has_many :comments, through: :posts
#post.rb
belongs_to :user
has_many :comments
#comment.rb
belongs_to :post
Now you can do something like User.find(1).comments
and you'll get all comments made by said user.
Whether you should have this or not depends on your use-case; do you need to get all comments made by a user? if yes, then you should do that way. Otherwise your original models were fine.
Ruby on Rails - Adding comments to post
As a comment can belong to a single post only, you do not need an association table (post_comments). You just need a simple one-to-many relationship.
Your post comment would be:
class Post < ActiveRecord::Base
has_many :comments
...
end
And comment would be like this:
class Comment < ActiveRecord::Base
belongs_to :post
...
end
Just make sure that you have the necessary post_id
column in the comments
table (you can check the db/schema.rb
file). If that is missing, you can use the following migration to add it:
class AddPostIdToComments < ActiveRecord::Migration
def change
add_column :comments, :post_id, :integer
add_index :comments, :post_id
end
end
You also need to make sure you keep somewhere the reference to the post, whenever a user tries to create a comment to a post. You can add this in a hidden field to your comments/new.html.erb
template. You could set the hidden field in the new
action, in PostsController, after passing it through the URL.
So, in your posts/show.html.erb
template you would have:
<%= link_to "Add Comment", new_comment_path(post_id: @post.id) %>
In your new
action, in PostsController
:
def new
@comment = Comment.new(post_id: params[:post_id])
end
And finally the hidden field in your form would be:
<%= f.hidden_field :post_id %>
Finally, add the post_id parameter to the list of permitted parameters in CommentsController
.
Related Topics
Array Attribute for Ruby Model
How to Define_Method in Rails Models
Rails Console Running Incredibly Slowly When Editing Text
Accessing Ruby Class Variables with Class_Eval and Instance_Eval
Using Question Mark Character in Rails/Activerecord Column Name
Multiple Robots.Txt for Subdomains in Rails
How to Run Ruby Tasks That Use My Rails Models
Puts Doesn't Print Stuff to Console
Error About Nokogiri While Capistrano Deployment on Ubuntu Server
Error Message "Xcode Alone Is Not Sufficient on Sierra"
Rails: Render Doesn't Work, Still Get 'Template Is Missing'
Rails How to Switch Between Dev and Production Mode