Rails AJAX Form Not Showing Up - javascript

I am trying to implement a contact form on my one-paged portfolio site using the mail_form gem and cannot seem to get the form to show up when using AJAX. I resorted to AJAX in place of the redirect_to approach because I do not want the site to refresh and scroll down to the anchor upon submission.
views/pages/home.html.erb:
<%= render 'contacts/new' %>
<div id="contact_form"></div>
config/routes.rb:
Rails.application.routes.draw do
root 'pages#home'
resources :contacts, only: [:new, :create]
end
models/contact.rb:
class Contact < MailForm::Base
attribute :name, validate: true
attribute :email, validate: /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i
attribute :message, validate: true
attribute :nickname, captcha: true
def headers
{
subject: "Regarding Your Portfolio",
to: "email (removed for privacy)",
from: %("#{name}" <#{email}>)
}
end
end
controllers/contacts_controller.rb:
class ContactsController < ApplicationController
before_action :contact_params, only: [:new, :create]
def new
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
#contact.request = request
if #contact.deliver
respond_to do |format|
# format.html {redirect_to root_path(anchor: "contact"), notice: 'Thank you for your message! I will get back to you shortly.'}
format.html {flash.now[:notice] = 'Thank you for your message! I will get back to you shortly.'}
format.js {render partial: 'contacts/new'}
end
else
respond_to do |format|
format.html {flash.now[:alert] = 'Your message could not be sent. Please try again.'}
format.js {}
end
end
end
private
def contact_params
params.require(:contact).permit(:name, :email, :message, :nickname, :captcha)
end
end
controllers/pages_controller:
class PagesController < ApplicationController
def home
#contact = Contact.new
end
end
contacts/_new.js.erb:
document.querySelector('#contact_form').innerHTML = '<%= j render 'new', locals: {contact: #contact} %>'
contacts/_new.html.erb:
<div class="row">
<div class="mb-md-0 mb-5">
<%= form_for #contact, id: 'contact_form', remote: true do |f| %>
<div class="row">
<div class="col-2"></div>
<div class="col-md-4">
<div class="md-form mb-0">
<%= f.text_field :name, required: true, class: 'form-control', placeholder: "Name" %>
</div>
</div>
<div class="col-md-4">
<div class="md-form mb-0">
<%= f.text_field :email, required: true, class: 'form-control', placeholder: "Email" %>
</div>
</div>
</div>
<div class="row">
<div class="col-2"></div>
<div class="col-md-8">
<div class="md-form mt-4">
<%= f.text_area :message, rows: 8, required: true, class: 'form-control md-textarea', placeholder: "Message"%>
</div>
</div>
</div>
<div class= "hidden d-none">
<%= f.text_field :nickname %>
</div>
<div class="text-center text-md-left">
<%= f.submit 'Send Message', class: 'btn btn-outline-secondary btn-sm col-3 mt-4 mx-auto' %>
</div>
<% end %>
</div>
</div>
The form works, but I would love to figure out why AJAX isn't working for it. I have searched for many hours and have also copied code from a previous application of mine that uses AJAX for a form to no avail. I want to be able to have the same effect as redirect_to root_path without having to reload the page and auto-scroll to the anchor. I have also tried copying the create method from the contacts_controller to the pages_controller with no success either. Any tips would be greatly appreciated!

Related

Rails 6 Ajax page keeps refreshing when creating category

I'm new to RoR and i have this problem in Rails 6 where i am trying to add a category to a categories list with ajax so that when i submit my form, the page shouldn't refresh. But it keeps refreshing.
I followed this tutorial and split the list of into a _category.html.erb partial and created a create.js.erb file that appends to the list but i don't get the same results.
here is my index.html.erb:
<body>
<main>
<section class="hero is-link is-fullheight pt-3">
<div class="hero-body">
<div class="container is-align-self-flex-start">
<h1 class="title has-text-centered">categories</h1>
<!-- container for the list of categories -->
<div class="container" id='category'>
<%= render #category %>
</div>
<h2 class="is-size-4">add a category</h2>
<%= render 'form', category: #category %>
</div>
</div>
</section>
</main>
</body>
this is my category list partial:
<!-- Loop over categories and add delete btn-->
<% #categories.each do |category| %>
<div class="columns is-mobile card mb-4">
<div class="column is-align-self-center ">
<p class="is-size-5"><%= category.name %></p>
</div>
<div class="column is-narrow">
<button class="button is-danger"><%= link_to 'delete', category, method: :delete, data: { confirm: 'Er du sikker?' } %></button>
</div>
</div>
<% end %> <!-- end of loop -->
this is my form partial for the input and submit btn:
<%= form_with(model: category) do |form| %>
<% if category.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(category.errors.count, "error") %> prohibited this category from being saved:</h2>
<ul>
<% category.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field has-addons">
<%= form.text_field :name , ({:class => "input", })%>
<%= form.submit "add", ({:class => "button is-primary", })%>
</div>
<% end %>
this is my create method in my categories controller that i suspect is the culprit because when i remove the format.html and format.json i get
"ActionController::UnknownFormat in CategoriesController#create"
def create
#categories = Category.all
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.js
format.html { redirect_to action: "index", notice: "Category was successfully created." }
format.json { render :show, status: :created, location: #category }
else
format.html { render :"index", status: :unprocessable_entity }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
this is the js file to append the new category to the list:
var body = document.getElementByID("category");
body.innerHTML = "<%= j render #categories %>" + body.innerHTML;
I have tried
This tutorial with jquery also but that also reloads on submit.
I have triple checked that i don't have "local:true" anywhere.
Changed tried #category instead of #categories in some places with no luck
I generated the project with a scaffold
Is there something that i'm missing?
Any guidance is greatly appreciated.
You are not using data-remote attribute for your form. This attribute means the form will submit the results via Ajax.

Active Storage failing to upload image attachment with AJAX Rails 5.2

I'm receiving Module::DelagationError (size delegated to attachment, but attachment is nil): for the create method in my posts_controller.rb when posting an AJAX based form with Active Storage. How can I fix my code to allow Active Storage to create the post with the image in an AJAX created container?
post.rb
has_one_attached :photo
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 post_path}
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:body_text, :photo, :user_id, :post_id)
end
post/_form.html.erb
<%= simple_form_for(#post, html: {multipart: true}, remote: true, authenticity_token: true) do |f| %>
<%= f.error_notification %>
<div class="row">
<div class="col">
<div class="-textarea">
<%= f.input :body_text, as: :text, class: 'form-control post-placeholder post-txt-area', label: false, placeholder: 'Write a post', style: "overflow: hidden; resize: none;", input_html: {:maxlength => 100, data: {:'meteor-emoji' => 'true'}} %>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-5">
<%= f.button :submit, 'Post', class: 'form-control submit-button bttn-gradient bttn-md bttn-royal', :data => {:disable_with => 'Posting .'} %>
</div>
<div class="col-md-5">
<label class="bttn-minimal bttn-md bttn-red">
Add Photo
<span style="display:none;">
<%= f.input :photo, as: :file, label: false, input_html: {accept: 'image/*'} %>
</span>
</label>
<% if f.object.photo.attached? %>
<%= image_tag(url_for(f.object.photo), class: 'img-responsive img-thumbnail') %>
<% end %>
<div class="preview-container">
<img id="img_prev" width="100" height="100" src="#" alt="preview" class="img-thumbnail d-none"/> <br/>
<a href="#" id="cancel_img_btn" class="d-none" onclick="return !(document.getElementById('post_photo').innerHTML=document.getElementById('post_photo').innerHTML);">Cancel
Upload</a>
</div>
</div>
</div>
<% end %>
Server Development Log
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"yiPHWZDBoFZOxLyNh8AphWOX5regegegeRXVGtz7mFeMdA/ZKAiiaCYjpJ/UOQ0n820gK0m5ZoKpFd483QFt+bnFDgGrLA==", "post"=>{"body_text"=>"oook!"}, "commit"=>"Post"}
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1
ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(1.0ms) BEGIN
(0.0ms) ROLLBACK
Completed 500 Internal Server Error in 9ms (ActiveRecord: 3.0ms)
Module::DelegationError (size delegated to attachment, but attachment is nil):
You cannot send files using Ajax.
This is now all browsers work.
But you can used gem "remotipart" which can do a hack and behavior will be similar.

Ajax record delete not appended to HTML

I am venturing into AJAX and would like to delete a record of a model and followed this thread : How to perform Controller.destroy action asynchronously in rails?
models:
Photographe
Photographephoto
views/photographes/edit.html.erb
<div id="sectionimages" class="gutter-0 row" >
<% #photographe.photographephotos.all.each do |f| %>
<div class="col-md-2 col-sm-3 col-xs-6 col">
<%= link_to professionnel_photographe_photographephoto_path(#photographe.professionnel.id,#photographe.id, f.id), method: :delete, remote: 'true', id: "destruction"+f.id.to_s do %>
<div class="killimage" >
<%= image_tag f.image.url(:small) %>
<%= image_tag 'fatcrosswhite.svg', class: 'imgover' %>
</div>
<% end %>
</div>
<% end %>
</div>
link to Photographephotos#destroy is remote and there's an id like "destruction134"
photographephotos_controller.rb
def destroy
#imagedestroyed = Photographephoto.find(params[:id])
#imagedestroyedid = #imagedestroyed.id
#imagedestroyed.image = nil
#imagedestroyed.save
#imagedestroyed.destroy
respond_to do |format|
format.js
end
end
views/photographephotos/destroy.js.erb
var destroyelement = document.getElementById("<%= "destruction"+#imagedestroyedid.to_s %>");
destroyelement.parentNode.remove();
Problem is the file is indeed deleted but I have to refresh the page to see it removed. It seems the javascript is not effective. (I am trying to remove the parent of the link which is a Bootstrap DIV)

RoR - Convert submit form to AJAX from

I have a form that works well. Here is my partial:
<%= form_for #reservation, url: {controller: 'reservations', action: 'create'} do |f| %>
<div class="row">
<div class="col-sm-8 col-sm-offset-1">
<div class="form-group">
<%= f.text_field :name, class: 'form-control', id: 'name', placeholder: 'Party Name', required: true %>
</div>
<div class="form-group">
<div class="col-sm-4">
Party Size:
</div>
<div class="col-sm-6">
1 <%= f.radio_button :party_size, '1'%>
2 <%= f.radio_button :party_size, '2'%>
</div>
</div>
<div class="col-sm-4 col-sm-offset-8">
<div class="form-group">
<%= f.submit 'submit', class: 'btn default-btn btn-block' %>
</div>
</div>
</div>
</div>
Here is the controller action create:
def create
#reservation = Reservation.new(reservation_params)
#reservation.customer_id = session[:customer_id]
if #reservation.save
redirect_to :back
else
render 'reservations/new'
end
end
I would like to render 'reservations/confirmation' in place of the current partial reservations/form. I know I need to add remote: true, to the form_for tag, but I get stuck there. What & where do I need to write in JS to make this submit function work with AJAX? What do I need to add to the create action?
You need to submit it via JQuery with $.post() and you also have to use respond_to to respond to both JavaScript submissions and normal HTML submissions (in case someone has JavaScript disabled).
http://guides.rubyonrails.org/working_with_javascript_in_rails.html#server-side-concerns
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.js   {}
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end

Rails & Zurb Modal Loads Entire Page On Edit

I'm trying to edit content from my rails app Products through a zurb foundation modal. I can add new just fine. But when trying click the edit button, it loads a modal with the whole page again. Although it loads the correct edit page, I just want an edit form. Not a whole new render of my site.
Products_controller.rb
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
#product = Product.new
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
#product = Product.find(params[:id])
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:name, :price)
end
end
index.html.erb
<h1>Listing products</h1>
Click Me For A Modal
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #products.each do |product| %>
<tr>
<td><%= product.name %></td>
<td><%= product.price %></td>
<td><%= link_to 'Show', product %></td>
<td><%= link_to 'Edit', edit_product_path(product) %></td>
<td><%= link_to 'EditM', edit_product_path(product), :remote => true, class: "", "data-reveal-id" => "editModal", "data-reveal-ajax" => edit_product_path(product) %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Product', new_product_path, class: "button radius", "data-reveal-id" => "addModal" %>
<div id="addModal" class="reveal-modal" data-reveal>
<%= render :partial => 'form', locals: { product: #products } %>
<a class="close-reveal-modal">×</a>
</div>
<div id="editModal" class="reveal-modal" data-reveal>
<%= render :partial => 'form' %>
<a class="close-reveal-modal">×</a>
</div>
_form.html.erb
<%= form_for(#product) do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="row">
<div class="small-3 columns">
<%= f.label :name, class: "right inline" %>
</div>
<div class="small-9 columns">
<%= f.text_field :name %>
</div>
</div>
<div class="row">
<div class="small-3 columns">
<%= f.label :price, class: "right inline", title: "Price In USD", data: { tooltip: true } %>
</div>
<div class="small-9 columns">
<%= f.text_field :price %>
</div>
</div>
<div class="row">
<div class="small-9 small-offset-3 columns">
<%= f.submit %>
</div>
</div>
<% end %>
Below is an image of how it loads after you select the EditM button.
I have updated my :edit method to the following. It appears to be working so it loads the action only, not the layout. Is this the proper way? Or should I be doing it differently?
def edit
#product = Product.find(params[:id])
render :layout => false
end
This is the modal in index.html.erb:
<div id="editModal" class="reveal-modal" data-reveal>
<a class="close-reveal-modal">×</a>
</div>

Categories

Resources