ajax rails form_with submits but only after page reload - ruby-on-rails

I've had an existing comment form on a resource show.html.erb that I want to be added to the show page without having to reload the entire page. I understand that with ajax via the 'form_with' form, this should be entirely possible.
My issue is that whilst the form does create a new comment, it only appears after I refresh the page.
I also get the following error.
ArgumentError (too few arguments):
app/controllers/comments_controller.rb:18:in 'format'
app/controllers/comments_controller.rb:18:in 'create'
comments_controller
class CommentsController < ApplicationController
before_action :load_commentable
before_action :authenticate_user!
before_action :comment_auth, only: [:edit, :update, :destroy]
...
def create
#comment = #commentable.comments.new(allowed_params)
#comment.user_id=current_user.id if current_user
if #comment.save
format.html { redirect_to #commentable, notice: "Comment added." }
format.js
else
render 'edit'
end
...
views/comments/create.js.coffee
comment = document.getElementById("comment")
comment.innerHTML = "<%= j render(#comment) %>"
views/comments/_form.html.erb
<%= form_with(model: [#commentable, #comment]) do |f| %>
<% if #comment.errors.any? %>
<div class="error_messages">
<h2>Please correct the following errors.</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<strong><%= f.label :name, :class=>'form-label' %></strong><br>
<%= f.text_field :name, value: current_user.fname, readonly: true, :class=>'form-control' %>
</p>
<p>
<strong><%= f.label :title, :class=>'form-label' %></strong><br>
<%= f.text_field :title, :class=>'form-control' %>
</p>
<p>
<strong><%= f.label :review, :class=>'form-label' %></strong><br>
<%= f.text_area :body, :class=>'form-control', rows: 5 %>
</p>
<p>
<%= f.submit :class=>'btn btn-success' %>
</p>
<% end %>

For me, I needed
<%= form_with(model: #message, method: :post, local: true) do |f| %>
local: true was necessary. All other combos didn't work remote: true, remote: false, local: false

as you know, form_with it's a remote form, you should not use redirect_to there. Please remove your block
if #comment.save
format.html { redirect_to #commentable, notice: "Comment added." }
format.js
else
render 'edit'
end
replace it to
if #comment.save
#status = "success"
end
And you can add a notice message to your views/comments/create.js.erb (it's not .js.coffee) with condition of #status (failed/success).
Hope this helps.

Related

Edit a comment in its association show

I have a Concert model and Comment model
The user directly write his comments in the concert show, but for any reasons he may want to edit it...
What is the easiest way to do this? I don't want to go to the edit view, but I'd rather prefer to edit it in the show page...
How or can I use the same form that I have in that show?
I was thinking of a modal but I am not sure it's friendy user...
Any help would be very welcome
concerts/show.html.erb
<h1><%= #concert.kountry%> - <%= #concert.city %> - <%= #concert.venue %> </h1>
<% #concert.comments.each do |c| %>
<%= c.user.email %>
<%= l(c.created_at, format: '%d/%m/%y - %H:%M:%S') %> - <%= link_to "Modifier", edit_concert_comment_path(c) %>
<%= simple_format(c.content) %>
<% end %>
<%= simple_form_for([#concert, #comment]) do |f| %>
<%= f.input :content, as: :text, placeholder: "your comment", label: false, input_html: { rows: 3 } %>
<%= f.submit "Send", class: "btn btn-success" %>
<% end %>
You can try using the Best In Place gem, hasn't been updated in a while but should still work.
modify form
<% #concert.comments.each do |comment| %>
<%= comment.user.email %>
<%= l(comment.created_at, format: '%d/%m/%y - %H:%M:%S') %>
<%= best_in_place(comment, :content, as: :textarea) %>
<% end %>
then modify controller
def update
#comment = Comment.find params[:id]
respond_to do |format|
if #comment.update(update_comment_params)
format.html { redirect_to(#comment, notice: 'Comment was successfully updated.') }
format.json { respond_with_bip(#comment) }
else
format.html { render action: "edit" }
format.json { respond_with_bip(#comment) }
end
end
end

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 form using form_for not submitting using post method

I have a comments resource nested in courses resource:
routes.rb:
..
resources :courses do
resources :comments, :only => [:new, :create]
end
..
I want to show the form to give comment in the show page of any course.
comments_controller.rb:
class CommentsController < ApplicationController
before_action :require_user
before_action :set_course, only: [:new]
def new
#comment = Comment.new
end
def create
#comment = Comment.new(comment_params)
#comment.course = Course.find(params[:course_id])
#comment.user = current_user
if #comment.save
flash[:success] = "Comment Posted"
redirect_to course_path(#comment.course)
else
flash[:error] = "Comment can't posted"
redirect_to course_path(#comment.course)
end
end
private
def set_course
#course = Course.find(params[:course_id])
end
def comment_params
params.require(:comment).permit(:body ,:rating, :course_id, :user_id)
end
end
I have put #comment = Comment.new in show action of my courses controller.
The form i am using in view is:
<%= form_for([#course, #comment], method: "post", :url => course_comments_path(#course, #comment) ) do |f| %>
<div class="rrating" style="width:140px;">
<%= f.radio_button(:rating, 1) %>
<%= f.label(:rating_1, "1") %>
<%= f.radio_button(:rating, 2) %>
<%= f.label(:rating_2, "2") %>
<%= f.radio_button(:rating, 3) %>
<%= f.label(:rating_3, "3") %>
<%= f.radio_button(:rating, 4) %>
<%= f.label(:rating_4, "4") %>
<%= f.radio_button(:rating, 5) %>
<%= f.label(:rating_5, "5") %>
</div>
<%= f.text_field :body, :class => "form-control", id: "exampleInputEmail1", placeholder: "Add a comment" %>
</fieldset>
<%= f.submit("Post", class: 'btn btn-success') %>
<% end %>
</form>
When i click on submit, a get request gets sent to the same page i am in currently(with all params in url).
I tried putting the form in a seperate new page for comments, it still dosen't work.
What am i doing wrong?
Ok, I got the problem and thought i should put it up for other's future reference.
The problem was that form_for was enclosed in form tags.
This might work, show page :
<%= form_for([#course, #course.comments.build] , method: :post) do |f| %>
<fieldset class="form-group" style="margin-top:0px; !important">
<div class="rrating" style="width:140px;">
<%= f.radio_button(:rating, 1) %>
<%= f.label(:rating_1, "1") %>
<%= f.radio_button(:rating, 2) %>
<%= f.label(:rating_2, "2") %>
<%= f.radio_button(:rating, 3) %>
<%= f.label(:rating_3, "3") %>
<%= f.radio_button(:rating, 4) %>
<%= f.label(:rating_4, "4") %>
<%= f.radio_button(:rating, 5) %>
<%= f.label(:rating_5, "5") %>
</div>
<%= f.text_field :body, :class => "form-control", id: "exampleInputEmail1", placeholder: "Add a comment" %>
</fieldset>
<%= f.submit("Post", class: 'btn btn-success') %>
<% end %>
comments controller :
def create
#course = Course.find(params[:course_id])
#comment = #course.comments.create(comment_params)
#comment.user = current_user
if #comment.save
flash[:success] = "Comment Posted"
redirect_to course_path(#comment.course)
else
flash[:error] = "Comment can't posted"
redirect_to course_path(#comment.course)
end
end
Since you are assigning a course to the comment in the create action manually, You can send the #comment object only to comment form and you can go to create action.
Send the course_id through a hidden field from the form to create action
<%= form_for #comment, url: course_comments_path do |f| %>
<fieldset class="form-group" style="margin-top:0px; !important">
<div class="rrating" style="width:140px;">
<%= f.radio_button(:rating, 1) %>
<%= f.label(:rating_1, "1") %>
<%= f.radio_button(:rating, 2) %>
<%= f.label(:rating_2, "2") %>
<%= f.radio_button(:rating, 3) %>
<%= f.label(:rating_3, "3") %>
<%= f.radio_button(:rating, 4) %>
<%= f.label(:rating_4, "4") %>
<%= f.radio_button(:rating, 5) %>
<%= f.label(:rating_5, "5") %>
<%= f.hidden_field :course_id, value: #course.id %
</div>
<%= f.text_field :body, :class => "form-control", id: "exampleInputEmail1", placeholder: "Add a comment" %>
</fieldset>
<%= f.submit("Post", class: 'btn btn-success') %>
<% end %>
Now you will get course_id through the params and assign that course to the comment.

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 %>

Rails - AJAX/JQuery not working

For my application, I have projects where users can make comment (class Newcomments) postings. Right now it posts great but on page refresh. I am trying to use AJAX/JQUERY so that it will post with no page refresh. I am following this railscasts tutorial.
So right now, the posts are made to my database and the page does not refresh. But when I refresh, the posts shows up. The page that I render my comments for a specific project is on the projects/_comments.html.erb.
Question: How would I adjust it so that it the new comment made renders?
newcomments_controller.rb
def create
#newcomment = #commentable.newcomments.new(params[:newcomment])
if #newcomment.save
respond_to do |format|
format.html { redirect_to comments_project_path(#commentable) }
format.js
end
else
render :new
end
end
view/newcomments/_form.html.erb
<span class="comment">
<%= form_for [#commentable, #newcomment], remote: true do |f| %>
<%= f.text_area :content, rows: 3, :class => "span8" %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.submit "Add Comment", :class => "btn btn-header" %>
<% end %>
</span>
view/newcomments/create.js.erb
$('#newcomment').append('<%= j render(#newcomments) %>');
projects_controller.rb
def comments
#commentable = #project
#newcomments = #commentable.newcomments.newest.page(params[:comments_page]).per_page(10)
#newcomment = Newcomment.new
respond_to do |format|
format.html # show.html.erb
format.json { render json: #project.comments }
end
end
projects/comments.html.erb
<%= render 'comments' %>
projects/_comments.html.erb
<%= render #newcomments %>
view/newcomments/_newcomment.html.erb
<div class="comments">
<%= link_to newcomment.user.name %></strong>
Posted <%= time_ago_in_words(newcomment.created_at) %> ago
<%= newcomment.content %>
</div>
<span class="comment">
<%= form_for [#commentable, #newcomment] do |f| %>
<div class="field">
<%= f.text_area :content, rows: 3, :class => "span8" %>
</div>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="actions">
<%= f.submit "Add Comment", :class => "btn btn-header" %>
</div>
<% end %>
<% unless newcomment.newcomments.empty? %>
<%= render #newcomments %>
<% end %>
</span>
Try binding AJAX actions as described here:
http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
Also, consider returning a render comments partial html instead of json comment object, to do so you need to tell in form after :remote directive that :'data-type'=>'html', so that returned html will hit function binded on AJAX success, and then swap html of container div with, for example, jQuery

Resources