Response for Form with custom action using ajax - ruby-on-rails

I want to upload the user avatar (carrierwave) using a custom action like this:
= form_for user, url: update_user_avatar_path(id: user.id), :html => {:class => "up-cl-ava-form", data: {type: :json}, novalidate: true, method: :put}, remote: true do |f|
= f.file_field :avatar_picture
= f.submit "Update", remote: true
In UsersController
def update_user_avatar
#user = User.find(params[:id]) || current_user
respond_to do |format|
if #user.update_attributes!(avatar_picture: params[:user][:avatar_picture])
format.json { render json: {}, status: :ok}
else
format.json { render json: {}, status: :unprocessable_entity}
end
end
end
Params in #update_user_avatar
{"utf8"=>"✓", "_method"=>"put",
"authenticity_token"=>"BPGeN5mpRCYwIco1YSsBx6IT7MfIBOdSlwS9Y5WJZeU=",
"user"=> {"avatar_picture"=>
#>}, "commit"=>"Update", "id"=>"30", "action"=>"update_user_avatar",
"controller"=>"users"}
Request
.... "CONTENT_TYPE"=>"multipart/form-data;
boundary=----WebKitFormBoundaryvz51HFYrromiuTS7" ....
In my JS
$(document).ready(function(){
$(".up-cl-ava-form").on("ajax:success", function(){
alert("success")
});
});
The problem here is that the image is uploaded correctly but the site redirects to lvh.me:3000/update_user_avatar?id=30 (blank page), instead staying in the same view.

This will be solve by adding remotipart gem
https://github.com/JangoSteve/remotipart

Related

Rails: Adding a post without refreshing the page

I'm new on ruby on rails.
I'm currently working on a facebook clone application and having trouble when adding a post without refreshing the page. Tried to create a post but the post did not show upon submitting and encountered Internal Server Error. When the page is refreshed, the newly created post is finally displayed.
Error in rails server
Completed 500 Internal Server Error in 50ms (ActiveRecord: 15.9ms | Allocations: 10085)
ActionView::Template::Error (First argument in form cannot contain nil or be empty):
1: = form_for([post, #comment]) do |f|
2: .form-bottom-button-container
3: .d-flex.comment-text-button
4: .p-2.flex-grow-1
Here are my codes. Please help me out. Thank you very much!
app/controllers/posts_controller.rb
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.js
format.html { redirect_to posts_path, notice: 'Successfully posted.'}
else
format.html { redirect_to posts_path, status: :unprocessable_entity }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
app/views/posts/create.js.haml
:plain
$("#post-display").append("#{escape_javascript(render 'post_display', post: #post)}");
app/views/posts/index.html.haml
-# All Posts
.col-8
.post-form
= render "post_form"
- if #posts.empty?
.post-card
.post-text
.no-post-text No posts to show
- else
#post-display
= render partial: "post_display", collection: #posts, as: :post
app/views/posts/_post_display.html.haml
.post-card
.post-text
.d-flex.justify-content-between
.d-flex
.post-user-image
- if post.user.profile_pic.present?
= image_tag post.user.profile_pic.url, class: "img img-fluid img-thumb"
- else
= image_tag "/default-user.jpg", class: "img img-fluid img-thumb"
.d-flex.flex-column
.username-bold= link_to post.user.username, profile_path(post.user.username)
.distance-date= distance_of_time_posted_in_words(post.created_at)
.post-edit-delete
- if post.user.username == current_user.username
= link_to edit_post_path(post), class: "text-space", remote: true, "data-bs-toggle" => "modal", "data-bs-target" => "#edit-post-#{post.id}-modal" do
%i.fa.fa-edit
.modal.fade(id="edit-post-#{post.id}-modal" tabindex="-1" aria-labelledby="edit-post-title" aria-hidden="true")
.modal-dialog.modal-dialog-centered.modal-dialog-scrollable
.modal-content
= link_to post, method: :delete, class: "text-space" do
%i.fa.fa-trash
.caption= post.caption
- if post.image.present?
= image_tag post.image.url, class: "img img-fluid img-fill"
-# Like Button
.row.container-margin-top
.col-6
- if liker(post)
= button_to post_like_path(post, liker(post)), method: :delete, class: "btn btn-maroon btn-wide btn-like-comment" do
%i.far.fa-thumbs-up
Unlike
- else
= button_to post_likes_path(post), method: :post, class: "btn btn-plain btn-wide btn-like-comment" do
%i.far.fa-thumbs-up
Like
.col-6
.btn.btn-plain.btn-wide.btn-like-comment.btn-comment
%i.far.fa-comment
%span Comment
-# Comment Section
.comment-box
.d-flex.justify-content-between
- unless post.likes.count == 0
.post-likes(type="button" data-bs-toggle="modal" data-bs-target="#likers-#{post.id}-modal")= "#{pluralize(post.likes.count, "like")}"
= render "layouts/likers_modal", post: post, index: post.id
.comment-toggle View Comments
.comment-display.hidden
= render "posts/comments", post: post
.comment-form
= render "comments/comment_form", post: post
app/views/comments/_comment_form.html.haml
= form_for([post, #comment]) do |f|
.form-bottom-button-container
.d-flex.comment-text-button
.p-2.flex-grow-1
= f.text_area :content, class: "comment-text-area comment", placeholder: "Write a comment..."
.p-2
= f.submit :Comment, class: "btn btn-maroon create-comment-button"
Check your application logs - it'll probably tell you the format.js method does not exist.
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.js # <----
format.html { redirect_to posts_path, notice: 'Successfully posted.'}
else
format.html { redirect_to posts_path, status: :unprocessable_entity }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
Just remove that line or use the format.json method and you're good to go.
To make the page not refresh you must submit the form using ajax request... you simply add remote: true to the form.
form_for([post, #comment], remote: true) do |f|
Also the error you are getting is because #comment is not being set.

Rails4 Form with remote - handling error message

I have a simple remote form like this:
= form_for :question, :url => question_path, :remote => true, :html =>{:class => 'question-form'} do |form|
and in my controller I check if in the form the EULA is accepted:
def create
if (params[:question][:eula] != 1)
puts "ERROR!"
respond_to do |format|
return format.json {render :json => {:error_message => "FOOOO", :success => false } }
end
end
#question = Question.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
How can I access :error_message or :success in my create.js.erb file?
You can do Ajax request
add id to form :id => "question-form"
= form_for :question, :url => question_path, :remote => true,
:html =>{:class => 'question-form', :id => "question-form"} do |form|
and anywhere in javascript file
$("#question-form").on("submit", function(e){
e.preventDefault();
var form = $(this);
var request = $.ajax({
method: "POST",
beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
url: "/questions",
dataType: "json",
data: form.serialize()
})
request.done(function(res){
console.log(res.success);
})
request.catch(function(jqXHR){
console.log(jqXHR.responseJSON)
})
})

Rails file_filed doesn't pass params

I have trouble with my image update
My form
= form_for #user, :html => {class: "form form_profile"} do |user|
= user.file_field :avatar
.... other fields
end
and controller update and user_avatar_params action
def update
respond_to do |format|
# binding.pry
if params[:user][:avatar]
if current_user.update(user_avatar_params)
flash[:notice] = 'Updated
format.html { render action: 'edit' }
format.js { render 'success_edit', layout: false }
....
end
def user_avatar_params
params.require(:user).permit(:avatar)
end
my params from console
{"utf8"=>"✓", "_method"=>"patch", "user"=>{"current_password"=>"", "password"=>""}, "action"=>"update", "controller"=>"users", "id"=>"2"}
i use paperclip
What wrong with it?
Try to add html: { multipart: true } code like in the example below.
<%= form_for #user, url: users_path, html: { multipart: true } do |form| %>
<%= form.file_field :avatar %>
<% end %>

Cannot get page to redirect?

I'm using Rails 4 and Dropzone.js to drag and drop files and upload them on form submission. I don't know why I can't get this to work but I'm trying to redirect after the form submits to a certain page but its not doing it (everything saves correctly though).
Here is my code:
items/new.html.haml > _form.html.haml
= form_for #item, validate: true,
html: {id: 'item-form', class: 'form-horizontal form', multipart: true} do |f|
= f.text_field :name
%main#image-preview
#dropzone
.fallback
= f.file_field :image, multiple: false
= f.submit 'Done', id: 'item-submit'
items.coffee
Dropzone.autoDiscover = false
if document.getElementById('item-form')
dropzone = new Dropzone('#item-form',
maxFiles: 1
maxFilesize: 1
paramName: 'item[image]'
headers: "X-CSRF-Token" : $('meta[name="csrf-token"]').attr('content')
addRemoveLinks: true
clickable: '#image-preview'
previewsContainer: '#image-preview'
thumbnailWidth: 200
thumbnailHeight: 200
autoProcessQueue: false
uploadMultiple: false)
$('#item-submit').on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
if dropzone.getQueuedFiles().length > 0
dropzone.processQueue()
else
$getScript '/items'
return
items_controller.rb
def continue
#item = Item.find(params[:id])
if #item.user_id == current_user.id
respond_to do |format|
format.html
format.xml
format.json { render :json => {} }
end
end
end
def new
#item = current_user.items.build
end
def create
#item = current_user.items.build(item_params)
respond_to do |format|
if #item.save
format.json { render :json => "window.location = #{post_continue_item_path(#item).to_json}" }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
routes.rb
resources :items do
get '/post/continue', to: 'items#continue', on: :member
end
log
Started POST "/items" for 127.0.0.1 at 2015-10-06 12:23:35 -0700
Processing by ItemsController#create as JSON
............
Completed 200 OK in 1786ms (Views: 0.2ms | ActiveRecord: 10.6ms)
Not sure where to go with this so how do I redirect when its giving me a JSON call?
JSON is not Javascript. It is designed to pass some data, not a working code. Check the response with your browser's developer tools, you will see your 'window.location' script nicely wrapped and basically unable to do anything - it should come as a mere string.
If you want a pure, classical HTTP redirect, you should look into redirect_to Rails method as your only response, and never try to render a JSON when you actually need a redirect.

I'm receiving a 406 error on ajax return

I'm new to rails so I'm probably messing this up somehow (obviously). I have a form that is sending the submission back to the controller via ajax. The data is getting there and getting into the db. The goal is that on successful submission the data will be returned in an html format that I can then prepend to page without causing a page refresh.
Here's my controller:
# POST /projects
# POST /projects.json
def create
#project = Project.new(params[:project])
#project.user_id = current_user.id
respond_to do |format|
if #project.save
#format.html { redirect_to #project, notice: 'Project was successfully created.' }
#format.json { render json: #project, status: :created, location: #project }
render :partial => "projects/project", :locals => { :project => #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
My ajax function looks like this:
$('#new_project').submit(function(){
$.ajax({
type: 'post',
beforeSend: setHeader,
url:'/projects',
dataType: 'json',
data: $('#new_project').serialize(),
success: function(json) {
console.log(json);
parent.jQuery('#cboxClose').click();
}
});
return false;
});
And finally, my partial. The partial is part of a loop. The loop works great and there's no problem there. The loop looks like this:
<% #projects.each do |project| %>
<%= render :partial => "project", :object => project %>
<% end %>
And the partial looks like this:
<section class="project">
<p class="name"><span>Name: </span> <%= project.name %></p>
<p class="title"><span>Title: </span><%= project.title %></p>
<p class="title"><span>User ID: </span><%= project.user_id %></p>
<article>
<span>Details:</span> <%= project.details %>
</article>
<article>
<p>Meta:</p>
<%= link_to 'Show', project %>
<%= link_to 'Edit', edit_project_path(project), :data => { :colorbox => true,:colorbox_height => '500px', :colorbox_width => '500px', :colorbox_iframe => true } %>
<%= link_to 'Destroy', project, method: :delete, data: { confirm: 'Are you sure?' } %>
</article>
</section>
So that's it. I thought I was on the right track but the 406 error is throwing me for a loop.
You send ajax request and your application should return javascript (or json) back to browser. But you call "render" and response has html type. So 406 error is.
If you want to render partial after success ajax call you should slightly change your controller (consider using format.js against format.json).
Controller:
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.js #render create.js.erb
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
And you should create file create.js.erb in directory with views of this controller with something like that:
$("div#that_you_wat_to_update").html("<%= escape_javascript render(:partial => 'projects/project', :locals => { :project => #project }) %>");
P.S. If you really want to respond with json, than you should update your ajax call to process the json response, but it's another story.

Resources