I'm developing a simple blogger app and I'm trying to add comment functionality to it. I'm trying to add delete/edit functionality to the comment, but I don't know how to get id of the comment I'm trying to edit. Here is what html code looks like:
<div class = "comment">
<p class = "author">Comment by <%= comment.author_name %>
<span class="creationTime"> <%= distance_of_time_in_words(comment.created_at, Time.now) %> ago</span>
</p>
<p class="text"><%= comment.body %></p>
<div class = "Button">
<%= link_to "Edit this comment", edit_article_comment_path(#comment.article_id, #comment.id) %>
</div>
</div>
Article controller show action:
def show
#article = Article.find(params[:id])
#comment = Comment.new
#comment.article_id = #article.id
end
Routes:
article_comments GET /articles/:article_id/comments(.:format) comments#index
POST /articles/:article_id/comments(.:format) comments#create
new_article_comment GET /articles/:article_id/comments/new(.:format) comments#new
edit_article_comment GET /articles/:article_id/comments/:id/edit(.:format) comments#edit
article_comment GET /articles/:article_id/comments/:id(.:format) comments#show
PATCH /articles/:article_id/comments/:id(.:format) comments#update
PUT /articles/:article_id/comments/:id(.:format) comments#update
DELETE /articles/:article_id/comments/:id(.:format) comments#destroy
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
root GET / articles#index
Error I get:
No route matches {:action=>"edit", :article_id=>"1", :controller=>"comments", :id=>nil} missing required keys: [:id]
Sorry if I'm asking a stupid question, I'm very new to this
You article controller should be look like:
def show
#article = Article.find(params[:id])
#comments = #article.comments
end
Your view should be look like:
<% #comments.each do |comment| %>
<div class = "comment">
<p class = "author">Comment by <%= comment.author_name %>
<span class="creationTime">
<%= distance_of_time_in_words(comment.created_at, Time.now) %> ago
</span>
</p>
<p class="text"><%= comment.body %></p>
<div class = "Button">
<%= link_to "Edit this comment", edit_article_comment_path(#article, comment) %>
</div>
</div>
<% end %>
Add has_many association to Article model as well.
has_many :comments
Hope you have added article_id to comments table
Try this ......
<div class = "Button">
<%= link_to "Edit this comment", edit_article_comment_path(#article.id, #comment.id) %>
</div>
In place of
<div class = "Button">
<%= link_to "Edit this comment", edit_article_comment_path(#comment.article_id, #comment.id) %>
</div>
Hope this will work for you.
Related
My discussions are nested within my projects. Projects is a basic CRUD and I'm trying to make discussions the same. They originally worked, but now I'm trying to add "edit" and "destroy" and I'm getting this error: No route matches {:action=>"edit", :controller=>"discussions", :format=>nil, :id=>nil, :project_id=>#<Discussion id: 24, title: "hello", description: "hello", created_at: "2015-02-02 20:58:53", updated_at: "2015-02-02 20:58:53", project_id: 12>} missing required keys: [:id]
for this line of code here <%= link_to "Edit", edit_project_discussion_path(item) %>.
discussions_controller.rb
class DiscussionsController < ApplicationController
def new
#project = Project.find(params[:project_id])
#discussion = Discussion.new
end
def create
#project = Project.find(params[:project_id])
#discussion = #project.discussions.build(discussion_params)
if #discussion.save
redirect_to new_project_discussion_path(#project)
end
end
def edit
#discussions = Discussion.find(params[:project_id])
end
def update
#discussions = Discussion.find(params[:project_id])
if #discussions.update_attributes(discussion_params)
redirect_to new_project_discussion_path
else
render "edit"
end
end
def destroy
#discussions = Discussion.find(params[:project_id])
#discussions.destroy
redirect_to new_project_discussion_path
end
def discussion_params
params.require(:discussion).permit(:project_id, :title, :description)
end
end
_form.html.erb
<%= form_for [#project, #discussion] do |f| %>
<div class="container">
Project: <%= #project.title %> <%= link_to "Go back?", projects_path %>
<hr>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Submit discussion", class: "btn btn-primary" %>
</div>
</div>
<% end %>
edit.html.erb
<%= render "form" %>
new.html.erb
<div class="container">
<div class="page-header">
<h1>Discussions<small> Discuss the project.</small></h1>
</div>
</div>
<%= render "form" %>
<% if !#project.discussions.blank? %>
<% for item in #project.discussions %>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<%= item.title %>
</div>
</div>
<div class="panel-body">
<p>
<%= item.description %> <br>
<%= link_to "Comment", new_discussion_comment_path(item) %>
<%= link_to "Delete", item, :method => :delete %>
<%= link_to "Edit", edit_project_discussion_path(item) %> |
</p>
</div>
</div>
<% end %>
<% end %>
Routes:
Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
homes GET /homes(.:format) homes#index
POST /homes(.:format) homes#create
new_home GET /homes/new(.:format) homes#new
edit_home GET /homes/:id/edit(.:format) homes#edit
home GET /homes/:id(.:format) homes#show
PATCH /homes/:id(.:format) homes#update
PUT /homes/:id(.:format) homes#update
DELETE /homes/:id(.:format) homes#destroy
project_discussions GET /projects/:project_id/discussions(.:format) discussions#index
POST /projects/:project_id/discussions(.:format) discussions#create
new_project_discussion GET /projects/:project_id/discussions/new(.:format) discussions#new
edit_project_discussion GET /projects/:project_id/discussions/:id/edit(.:format) discussions#edit
project_discussion GET /projects/:project_id/discussions/:id(.:format) discussions#show
PATCH /projects/:project_id/discussions/:id(.:format) discussions#update
PUT /projects/:project_id/discussions/:id(.:format) discussions#update
DELETE /projects/:project_id/discussions/:id(.:format) discussions#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
discussion_comments GET /discussions/:discussion_id/comments(.:format) comments#index
POST /discussions/:discussion_id/comments(.:format) comments#create
new_discussion_comment GET /discussions/:discussion_id/comments/new(.:format) comments#new
edit_discussion_comment GET /discussions/:discussion_id/comments/:id/edit(.:format) comments#edit
discussion_comment GET /discussions/:discussion_id/comments/:id(.:format) comments#show
PATCH /discussions/:discussion_id/comments/:id(.:format) comments#update
PUT /discussions/:discussion_id/comments/:id(.:format) comments#update
DELETE /discussions/:discussion_id/comments/:id(.:format) comments#destroy
discussions GET /discussions(.:format) discussions#index
POST /discussions(.:format) discussions#create
new_discussion GET /discussions/new(.:format) discussions#new
edit_discussion GET /discussions/:id/edit(.:format) discussions#edit
discussion GET /discussions/:id(.:format) discussions#show
PATCH /discussions/:id(.:format) discussions#update
PUT /discussions/:id(.:format) discussions#update
DELETE /discussions/:id(.:format) discussions#destroy
root GET / homes#index
I'm unsure if any of my projects_controller.rb info is needed but if so I will update.
edit_project_discussion_path requires a Project and a Discussion.
/projects/:project_id/discussions/:id/edit(.:format)
You are only sending the Discussion item as the project parameter.
<%= link_to "Edit", edit_project_discussion_path(item) %>
You need to change that to include the project:
<%= link_to "Edit", edit_project_discussion_path(#project, item) %>
I'm trying to add comment functionality of my Reddit clone. This is the comments controller that creates a comments and adds it to a post.
class CommentsController < ApplicationController
def new
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
#comment = Comment.new
#authorize #comment # from include Pundit in the application controller, authorize is an inherited method
end
def create
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
#comment = current_user.comments.build(comment_params)
end
private
def comment_params
params.require(:comment).permit(:text)
end
end
I'm trying to add a comments field for every post page by using a form partial that looks like this:
<%= form_for [topic, post] do |f| %>
<%= form_group_tag(comment[:text]) do %>
<%= f.label :text %>
<%= f.text_area :text, rows: 10, class: 'form-control', placeholder: "Enter your comment" %>
<% end %>
<div class = "form-group">
<%= f.submit "Save", class: 'btn btn-success' %>
</div>
<% end %>
This form partial should appear at the post.show.html.erb so I put it there
<h1><%= markdown #post.title %></h1>
<div class="row"> <!-- what others are there besides row? -->
<div class="col-md-8">
<p><%= markdown #post.body %></p>
</div>
<div class="col-md-4">
<% if policy(#post).edit? %>
<%= link_to "Edit", edit_topic_post_path(#topic, #post), class: 'btn btn-success' %>
<% end %>
</div>
<div class="col-md-8">
<%= render partial: 'comments/form', locals: { topic: #topic, post: #post, text: #post.comments.new } %>
</div>
</div>
but I'm getting a NameError for my 'comment' on the form_group_tag line. Most of what I defined here comes from my code for adding new posts, which seemed to work. Is there something missing here?
I fixed my name error by adding comments to the form_for line, but I'm getting NoMethodError for my topic,post,comment path, so I thought it'd be helpful to add what rake routes is pulling up.
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
user_confirmation POST /users/confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /users/confirmation/new(.:format) devise/confirmations#new
GET /users/confirmation(.:format) devise/confirmations#show
user PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
topic_posts POST /topics/:topic_id/posts(.:format) posts#create
new_topic_post GET /topics/:topic_id/posts/new(.:format) posts#new
edit_topic_post GET /topics/:topic_id/posts/:id/edit(.:format) posts#edit
topic_post GET /topics/:topic_id/posts/:id(.:format) posts#show
PATCH /topics/:topic_id/posts/:id(.:format) posts#update
PUT /topics/:topic_id/posts/:id(.:format) posts#update
DELETE /topics/:topic_id/posts/:id(.:format) posts#destroy
topics GET /topics(.:format) topics#index
POST /topics(.:format) topics#create
new_topic GET /topics/new(.:format) topics#new
edit_topic GET /topics/:id/edit(.:format) topics#edit
topic GET /topics/:id(.:format) topics#show
PATCH /topics/:id(.:format) topics#update
PUT /topics/:id(.:format) topics#update
DELETE /topics/:id(.:format) topics#destroy
post_comments POST /posts/:post_id/comments(.:format) comments#create
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
about GET /about(.:format) welcome#about
root GET / welcome#index
BTW: how does this routes.rb file look?
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:update]
resources :topics do
resources :posts, except: [:index]
end
resources :posts do
resources :comments, only: [:create]
end
end
Try:
<%= render partial: 'comments/form', locals: { topic: #topic, post: #post, comment: #post.comments.new } %>
...
<%= form_for [post, comment] do |f| %>
<%= f.label :text %>
<%= f.text_area :text, rows: 10, class: 'form-control', placeholder: "Enter your comment" %>
<%= f.submit "Save", class: 'btn btn-success' %>
<% end %>
...
If it does not help, try to temporary comment form_group_tag and send error here
It seems like you're sending the comment down to the partial as text.
... locals: { topic: #topic, post: #post, text: #post.comments.new } %>
^^^^
And by the way you're not saving the comment in the create action.
I'm pretty much an amateur when it comes to Rails. I got this to work, however I feel like the code is not efficient enough.
Is there any way to speed this up? And also it this how a professional would do it?
Controller
def mark_read
#topic = Topic.find(params[:id])
#topic.mark_as_read! :for => current_user
redirect_to user_path(current_user.slug)
end
def mark_all_read
Topic.mark_as_read! :all, :for => current_user
redirect_to user_path(current_user.slug)
end
Routes
resources :users do
member do
post :mark_read
post :mark_all_read
end
end
View
<% if current_user.id == #user.id %>
<%= link_to "Mark all as read", mark_all_read_user_path, :method=> :post %>
<h4> List of posts unread by you </h4>
<% #unread.each do |topic| %>
<% if #user.following?(Product.find(topic.product_id)) %>
<li> <%= topic.title %> <%= link_to "Mark as read", mark_read_user_path(topic), :method=> :post %> </li>
<% end %>
<% end %>
Is there someway that I could call an action in the controller without a route? I feel it would make the workflow neater.
The answer to your question is no. You can not have access any action in the controller unless it has a route, or its a CRUD generated by default, for example:
resources :articles
generates
Controller#Action
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
**ARTICLE CONTROLLER** //controller
class ArticlesController < ApplicationController
def index
#article=Article.all
end
def show
#article=Article.find(params[:id])
#comment = Comment.new
#comment.article_id = #article.id
end
def new
#article=Article.new
end
def create
#article = Article.new(article_params)
#article.save
redirect_to article_path(#article)
end
def destroy
article=Article.find(params[:id])
article.destroy
redirect_to articles_path
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
#article.update(article_params)
flash.notice = "Article '#{#article.title}' Updated!"
redirect_to article_path(#article)
end
def article_params
params.require(:article).permit(:title, :body)
end
end
**SHOW.HTML.ERB** /view file
<h1><%=#article.title%></h1>
<p><%=#article.body%></p>
<br><hr>
<%= link_to "edit", edit_article_path(#article) %>|
<%= link_to "delete",article_path(#article), method: :delete,data: {confirm: "Really delete the article?"} %>|
<%= link_to "<< Back to Articles List", articles_path %>
<h3>Comments</h3>
<%= render partial: 'articles/comment', collection: #article.comments %>
<%= render partial: 'comments/form' %>
**_FORM.HTML.ERB** //_form view
<h3>Post a Comment</h3>
<%= form_for [ #article, #comment ] do |f| %>
<p>
<%= f.label :author_name %><br/>
<%= f.text_field :author_name %>
</p>
<p>
<%= f.label :body %><br/>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
rake routes:
Prefix Verb URI Pattern Controller#Action
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
root GET / articles#index
comments GET /comments(.:format) comments#index
POST /comments(.:format) comments#create
new_comment GET /comments/new(.:format) comments#new
edit_comment GET /comments/:id/edit(.:format) comments#edit
comment GET /comments/:id(.:format) comments#show
PATCH /comments/:id(.:format) comments#update
PUT /comments/:id(.:format) comments#update
DELETE /comments/:id(.:format) comments#destroy
i get no articles_comments_path!
NoMethodError in Articles#show
Showing /home/manoj/ror/blogger/app/views/comments/_form.html.erb where line #3 raised:
undefined method article_comments_path' for #<#<Class:0x00000005be3d40>:0x000000054cacc0>
app/views/comments/_form.html.erb:3:in_app_views_comments__form_html_erb__3077497298558231225_47236640'
app/views/articles/show.html.erb:11:in `_app_views_articles_show_html_erb__4529829459036724249_48053660'
You are getting this error because you don't have article_comments_path helper method. Change your routes to this:
resources :articles do
resources :comments
end
OR
If you don't want to nest routes then change your form to this:
<%= form_for #comment do |f| %>
// form fields
<% end %>
Also in show action you can dry up your code by using association methods
def show
#article= Article.find(params[:id])
#comment = #article.comments.build
end
I am learning rails by following the rails 3 guide.
The blog application have ran now,however I want to make the comment editable,and make the update ,create form both in the post show page. so I make the following modifiation:
post.show.htm.erb:
<h2>Comments</h2>
<% #post.comments.each do |comment| %>
<tr>
<td><%= comment.commenter %></td>
<td><%= comment.body %></td>
<td><%= link_to 'Edit', edit_post_comment_path(#post,comment) %></td>
<td><%= link_to 'Destroy', post_comment_path(#post,comment), confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
<h2>Add a comment:</h2>
#here,I can not set the form_for property.
<%= form_for([#post,#comment],:url=>post_comment_path) do |f| %>
<div class="field">
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
The controller controller:
class CommentsController < ApplicationController
# GET /posts/1/comments/1/edit
def edit
#render json: params
#post=Post.find(params[:post_id])
#comments=Comment.all
#comment = Comment.find(params[:id])
render "/posts/show"
end
#other action omitted
def show
# I donot know what to do here
end
end
However I can not access the link:
http://localhost:3000/posts/1
I get the error:
No route matches {:action=>"show", :controller=>"comments"}
In fact,as you can see I have the show action in CommentController.
And,I wonder why it will access the comments#show action?
This is my routes:
post_comments GET /posts/:post_id/comments(.:format) comments#index
POST /posts/:post_id/comments(.:format) comments#create
new_post_comment GET /posts/:post_id/comments/new(.:format) comments#new
edit_post_comment GET /posts/:post_id/comments/:id/edit(.:format) comments#edit
post_comment GET /posts/:post_id/comments/:id(.:format) comments#show
PUT /posts/:post_id/comments/:id(.:format) comments#update
DELETE /posts/:post_id/comments/:id(.:format) comments#destroy
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
home_index GET /home/index(.:format) home#index
root / home#index
The /posts/:id will trigger posts#show. why comments#show?
if u need to edit the post, then add
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update_attributes(params[:post])
redirect_to some_path and return
end
render 'edit' #error
end
the form for edit should send a PUT request to the server. rails maps the url and the request ( like GET/POST/PUT/DELETE) using the routes file to the controller actions.
here
PUT /posts/:id(.:format) posts#update
the request is PUT, controller is PostsController and the action is update.
also,
post GET /posts/:id(.:format) posts#show
u need to pass the http request from the form if its POST/PUT/DELETE.
u can do so for 'edit'
<%= form_for([#post,#comment],:url=>post_comment_path, :method => :put) do |f| %>
maps to the show request for PostsController. the format is html bydefault. for more info, have a detailed look at the server log.