Creating a Blog ruby on Rails - Problem Deleting Comments - ruby-on-rails

As I always type I am new to rails and programming in general so go easy. Thanks in advance.
I have successfully followed the initial tutorial from Ryan Bates on how to build a weblog in 15 minutes. If you don't know this tutorial takes you through creating posts and allowing for comments on those post. It even introduces AJAX through the creating and displaying comments on the posts show.html.erb page. All works great.
Here's the hiccup, when Ryan takes you though this tutorial he clears out the comments_controller and only shows the code for creating comments. I am trying to add back the ability to edit and destroy comments. Can't seem to get it to work, keeps deleting the actual post not the comment (log shows that I keep sending DELETE request to PostsController). Here is my code:
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create!(params[:comment])
respond_to do |format|
format.html { redirect_to #post }
format.js
end
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to(posts_url) }
format.xml { head :ok }
end
end
end
/views/posts/show.html.erb
<%= render :partial => #post %>
<p>
<%= link_to 'Edit', edit_post_path (#post) %> |
<%= link_to 'Destroy', #post, :method => :delete, :confirm => "Are you sure?" %> |
<%= link_to 'See All Posts', posts_path %>
</p>
<h2>Comments</h2>
<div id="comments">
<%= render :partial => #post.comments %>
</div>
<% remote_form_for [#post, Comment.new] do |f| %>
<p>
<%= f.label :body, "New Comment" %><br/>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit "Add Comment" %></p>
<% end %>
/views/comments/_comment.html.erb
<% div_for comment do %>
<p>
<strong>Posted <%= time_ago_in_words(comment.created_at) %> ago
</strong><br/>
<%= h(comment.body) %><br/>
<%= link_to 'Destroy', #comments, :method => :delete, :confirm => "Are you sure?" %>
</p>
<% end %>
routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :posts, :has_many => :comments
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end

meagar is on the right path, but since this is a nested route you have to do:
<%= link_to 'Destroy', [#post, comment], ... %>
So, you are passing the comment and the post and letting rails figure out the route based on your definitions.

In _comments.html.erb, change your link_to to
<%= link_to 'Destroy', comment, ... %>
IE, pass it the comment itself, not the entire #comments array.

Related

nested edit path not working

Trying to figure out the edit path within _comment.html.erb file.
Keep getting this error:
ActiveRecord::RecordNotFound in CommentsController#edit
Couldn't find Article with 'id'=#<Comment::ActiveRecord_Associations_CollectionProxy:0x007fcac37359e8>
Don't know how to figure how to write the correct path.
Comments Controller
class CommentsController < ApplicationController
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
redirect_to article_path(#article)
end
def show
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
end
def edit
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
end
def destroy
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
#comment.destroy
redirect_to article_path(#article)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
_comment.html.erb
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<p>
<%= link_to 'Edit', edit_article_comment_path(#article.comments, comment) %>
</p>
<p>
<%= link_to 'Show', [comment.article, comment] %>
</p>
<p>
<%= link_to 'Destroy Comment', [comment.article, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
routes
resources :articles do
resources :comments
end
How do I write the correct path?
Also, the earlier path I had was this:
<%= link_to 'Edit', edit_article_comment_path(#article, comment) %>
But it would turn up a blank edit form, ie, none of the text boxes had anything filled in ... hence why I tried the other path.
Any help would be appreciated.
Thank you.
Comment _form.html.erb
<%= form_for([#article, #article.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br>
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Article show.html.erb
<p>
<strong>Title:</strong>
<%= #article.title %>
</p>
<p>
<strong>Text:</strong>
<%= #article.text %>
</p>
<h2>Comments</h2>
<%= render #article.comments %>
<h2>Add a comment:</h2>
<%= render 'comments/form' %>
<%= link_to 'Edit', edit_article_path(#article) %> |
<%= link_to 'Back', articles_path %>
There's a problem in _comment.html.erb
<%= link_to 'Edit', edit_article_comment_path(#article.comments, comment) %>
It should be
<%= link_to 'Edit', edit_article_comment_path(#article, comment) %>
But it would turn up a blank edit form, ie, none of the text boxes had anything filled in
You should check if you are passing the proper values in form_for
<%= form_for [#article, #comment] do |f| %>
EDIT2
Well the problem is you are passing new instance of comment every time, Even with the edit action. That's why you are not getting any values in the form
<%= form_for([#article, #article.comments.build]) do |f| %>
Change it to
<%= form_for([#article, #comment]) do |f| %>
And make sure you are assigning #article and #comment in both new and edit action of CommentsController or from wherever you are rendering the comments/_form
class CommentsController < ApplicationController
def new
#article = Article.find(params[:article_id])
#comment = #article.comments.new
end
def edit
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
end
#...
end

Rails: validation on blog comments not working

I am trying to learn Rails by building a simple blog. I have made it possible to add comments with AJAX en I am now trying to validate the presence of a name and body in the comments. However, the validation is not working. When there are no errors the comment gets added like it should, but when I leave either 'name' or 'body' blank and try to add the comment, I get redirected to this weird flat HTML-version of the post I was trying to comment on (with a path like this: /posts/21/comments). I do not understand why this is happening instead of just the post page reappearing with an error message in it, and I would be very grateful to anyone that could help me out.
So here is the CommentsController:
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
if #comment.errors.any?
respond_to do |format|
format.html { render #post }
format.js
end
else
respond_to do |format|
format.html { redirect_to #post }
format.js
end
end
end
def destroy
#post = Post.find(params[:post_id])
#comment = Comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to #post }
format.js
end
end
private
def comment_params
params.require(:comment).permit(:name, :body)
end
end
Model:
class Comment < ActiveRecord::Base
belongs_to :post
validates_presence_of :body, :name
end
And comment part of show.html.erb:
<section id="comment-section">
<div id="comments">
<h2>Reacties</h2>
<%= render partial: #post.comments.reverse %>
</div>
<%= form_for [#post, Comment.new], remote: true, authenticity_token: true do |f| %>
<% if #comment && #comment.errors.any? %>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
<p>
<%= f.label :name, "Naam" %><br/>
<%= f.text_field :name %></br></br>
<%= f.label :body, "Reactie" %><br/>
<%= f.text_area :body %>
</p>
<p><%= f.submit "Verstuur" %></p>
<% end %>
</section>
And the _comment.html.erb partial:
<%= div_for comment do %>
<p>
<strong>
Posted <%= time_ago_in_words(comment.created_at) %> ago
</strong>
<br/>
<i><%= comment.name %>:</i>
<%= comment.body %>
</p>
<p>
<% if logged_in? %>
<%= button_to 'Delete', [comment.post, comment],
:method => :delete,
:class=> 'link-button',
remote: true,
data: { confirm: 'Are you sure?' }
%>
<% end %>
</p>
<% end %>
Finally, my routes.rb file:
Rails.application.routes.draw do
get 'static_pages/aboutme'
get 'static_pages/photos'
get 'sessions/new'
resources :posts do
resources :comments, only: [:create, :destroy]
end
get 'admin' => 'sessions#new'
post 'admin' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
get '/overmij' => 'static_pages#aboutme'
get '/fotos' => 'static_pages#photos'
root 'posts#index'
end
The error is on this line format.html { render #post } That line renders the comments.index as they are nested with in posts so you get post/:id/comments. If you want to render a view (from another controller) you have to do it like this:
render template "posts/show"
or just
render "posts/show"
But the thing about rendering a view/template is that it will not set any variables needed, so you'll get a error like #variable is nil so you need to set the variables needed for post/show. Another thing you can do is redirect_to #post but the thing about redirect is that it will refresh the page and erase what the user had typed in the text box.
These are rails docs on rendering/redirecting
Usually I use flash to display my error messages, something like this should work
Controller
respond_to do |format|
format.html { flash[:notice] = #comment.errors, render #post }
format.js
end
View
<%if notice.present? %>
<div class="alert alert-danger" role="alert">
<% notice.each do |msg| %>
<li><%= msg %></li>
<% end %>
</div>
<% end %>

How can I leave a comment and associate with the post in post' index page?

How can I leave a comment and associate with the post in post' index page?
It is my PostsController:
def index
#posts = Post.all
"what should I add here?"
end
# GET /posts/1
# GET /posts/1.json
def show
#comments = #post.comments.all
#comment = #post.comments.build
end
and its my posts show view:
<p id="notice"><%= notice %></p>
<p>
<h3><%= #post.name %></h3>
</p>
<p>
<%= (#post.descriptopm).html_safe %>
</p>
<%= link_to 'Edit', edit_post_path(#post), :class => "btn btn-info btn-xs" %>
<%= link_to 'Back', posts_path, :class => "btn btn-info btn-xs" %>
<h3>Comments</h3>
<% #comments.each do |comment| %>
<div>
<strong><%= comment.user_name %></strong>
<br />
<p><%= (comment.body).html_safe %></p>
</div>
<% end %>
<%= render 'comments/form' %>
and its my posts index view:
<h1>Listing posts</h1>
<%= link_to 'Create a New Post', new_post_path, :class => "btn btn-success btn-sm" %>
<% #posts.each do |post| %>
<div class="post thumbnail">
<h3><%= post.name %></h3>
<div><%= (post.descriptopm).html_safe %></div>
<div class="bottom-bottoms">
<%= link_to 'Display', post, :class => "btn btn-info btn-xs" %>
<%= link_to 'Edit', edit_post_path(post), :class => "btn btn-info btn-xs" %>
<%= link_to 'Delete', post, method: :delete, data: { confirm: 'Are you sure?' }, :class => "btn btn-info btn-xs" %>
</div>
<h3>Comments</h3>
<% post.comments.each do |comment| %>
<div>
<strong><%= comment.user_name %></strong>
<br />
<p><%= (comment.body).html_safe %></p>
</div>
<% end %>
<%= render 'comments/form' %>
</div>
<% end %>
the post.rb :
class Post < ActiveRecord::Base
has_many :comments
end
the comment.rb :
class Comment < ActiveRecord::Base
belongs_to :post
end
the show page's comment function looks right
but when I leave a comment in my post's index page
It might not save the comment with the right post's id
how do I fix it?
and onother one:
how can I redirect the page to the index page after I save the comment not to comment's index page?
How can I leave a comment and associate with the post in post' index
page?
There are several things to consider:
Comment Objects
Firstly, you need to appreciate that since Rails is an object orientated framework (by virtue of being built on Ruby), you will need to ensure your new comment corresponds with the relevant Post object
I think this the core of what you're getting confused about:
def index
#posts = Post.all
# Here needs to go your "comment" build methodology. Except, it only works *per* post ;)
end
The trouble you have is that you can't "build" a comment for Posts - you have to build them per post, like this:
#post = Post.find 2
#post.comments.new #-> allows you to create a new comment for that particular post
--
Implementation
The best solution I can give you will be somewhat constricted, but will serve your purposes correctly. Here it is:
#app/controllers/posts_controller.rb
Class PostsController < ApplicationController
def index
#posts = Post.all
#comment = Comment.new
end
end
#app/controllers/comments_controller.rb
Class CommentsController < ApplicationController
def create
#comment = Comment.new(comment_params)
#comment.save
end
private
def comment_params
params.require(:comment).permit(:comment, :params, :post_id)
end
end
This will take into consideration that for each comment on your index, you'll have a form with the post_id attached; and will be a "linear" flow (IE you can only post a single comment at a time):
#app/views/posts/index.html.erb
<% #posts.each do |post| %>
<%= post.title %>
<%= form_for #comment do |f| %>
<%= f.hidden_field :post_id, value: post.id %>
<%= f.text_field :title %>
<%= f.submit %>
<% end %>
<% end %>
Yes, this will give each Post a "new comment" form on your index page (hence my denoting its constriction). However, what it will do is give you the ability to add a comment for any of the posts on the page, handling them with the CommentsController
To answer your second second question, you can use
redirect_to post_index_path
As for the first question, you can set the post id of the post by using:
#post.comments.new
Instead of just Comment.new, which won't set the ID of the post.
In this scenario...this is the best example that you can get help
Railscasts show post with comments using polymorphism

Rails partial not rendering through ajax call

I am trying to render a partial through ajax when a user clicks on button destroying a relationship between two products. The destroy action works, but I can not get the rendering of the partial to work.
The partial is rendered on the edit page for a product:
edit.html.erb
<div id="relationship_form">
<%= render "relationships", product: #product %>
</div>
_relationships.html.erb
<%= render "unrelate", relationship: relationship %>
_unrelate.html.erb
<%= form_for(relationship,html: { method: :delete },remote: true) do |f| %>
<%= f.submit "Remove", class: "btn btn-small" %>
<% end %>
relationships_controller.html.erb
def destroy
...
respond_to do |format|
format.html { redirect_to edit_product_path }
format.js
end
end
destroy.js.erb
$("#relationship_form").html("<%= escape_javascript(render :partial => 'products/relationships', :locals => {:product => #product}) %>");
I have checked that the ajax call goes through to the destroy.js.erb, by inserting an alert, so there must be an error in the javascript?
Update:
I got it to work by moving the form in the _unrelate partial to the _relationship partial. Still not really clear why it made it work.
_relationships.html.erb
<%= form_for(relationship,html: { method: :delete },remote: true) do |f| %>
<%= f.submit "Remove", class: "btn btn-small" %>
<% end %>

No route matches when trying to edit

Here's the scoop: I've created a test app that allows users to create ideas and then add "bubbles" to these ideas. Currently, a bubble is just text. I've successfully linked bubbles to ideas. Furthermore, when a user goes to view an idea it lists all of the bubbles attached to that idea. The user can even delete the bubble for a given idea.
My problem lies in editing bubbles. When a user views an idea, he sees the idea's content as well as any bubbles for that idea. As a result, I've set all my bubble controls (editing and deleting) inside the ideas "show" view. My code for editing a bubble for an idea is <%= link_to 'Edit Bubble', edit_idea_bubble_path %>. I ran rake routes to find the correct path for editing bubbles and that is what was listed.
Here's my error: No route matches {:action=>"edit", :controller=>"bubbles"}
In my bubbles controller I have:
def edit
#idea = Idea.find(params[:idea_id])
#bubble = #idea.bubbles.find(params[:id])
end
def update
#idea = Idea.find(params[:idea_id])
#bubble = #idea.bubbles.find(params[:id])
respond_to do |format|
if #bubble.update_attributes(params[:bubble])
format.html { redirect_to(#bubble,
:notice => 'Bubble was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "Edit" }
format.xml { render :xml => #bubble.errors,
:status => :unprocessable_entity }
end
end
end
To go a step further, I have the following in my routes.rb file
resources :ideas do
resources :bubbles
end
So far everything seems to function except when I try to edit a bubble.
I'd love some guidance.
Thanks!
Here's my show.html.erb file for Ideas:
<h2>Bubbles</h2>
<% #idea.bubbles.each do |bubble| %>
<p>
<b>Bubble:</b>
<%= bubble.description %>
</p>
<p>
<%= link_to 'Edit Bubble', edit_idea_bubble_path (#idea) %>
</p>
<tb />
<p>
<%= link_to 'Delete Bubble', [bubble.idea, bubble],
:confirm => 'Are you sure you want to delete this bubble?',
:method => :delete %>
</p>
<% end %>
<h2>Add a bubble:</h2>
<%= form_for([#idea, #idea.bubbles.build]) do |f| %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %> </div><% end %>
Following edit_idea_bubble_path (#idea), here is the edit.html.erb file for Bubbles:
<%= render 'form' %>
<%= link_to 'Back to Ideas', ideas_path %>
And finally, my _form.html.erb file for Bubbles: this is where the problem lies, I believe
<% form_for([#idea, #idea.bubbles.build]) do |f| %>
<%= f.error_messages %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
First build the route in your show.html.erb file
<%= link_to 'Edit Bubble', edit_idea_bubble_path(#idea, bubble) %>
Then, your controller should have 2 objects for both #idea and #bubble
when action is new
#idea = Idea.find_by_id(:params[:idea_id])
#bubble = #idea.bubbles.build
when action is edit
#idea = Idea.find_by_id(:params[:idea_id])
#bubble = #idea.bubbles.find_by_id(:params[:bubble_id])
In your _form.html.erb
<% form_for([#idea, #bubble]) do |f| %>
You have to provide the idea and the bubble objects:
<%= link_to 'Edit Bubble', edit_idea_bubble_path(#idea,#bubble) %>
Update:
Edit the _form.html.erb file
<% form_for([#idea, #bubble]) do |f| %>

Resources