How to show a notice after submitting a simple form - javascript

I'm using Simple Form and Ajax and I want to show a notice(it can be flash) something like "Successfully Submitted", after successful submission of a form. How can I achieve this?
This my controller:
def create
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.user_id = current_user.id
#order.save
session[:order_id] = #order.id
end
and my form in views:
<%= form_for OrderItem.new, html: {class: "add-to-cart"}, remote: true do |f| %>
<div class="input-group">
<%= f.hidden_field :quantity, value: 1, min: 1 %>
<div class="input-group-btn">
<%= f.hidden_field :product_id, value: product.id %>
<%= f.submit "Add to Cart", data: { confirm: 'Are you sure?'}, class: "btn btn-default black-background white" %>
</div>
</div>
<% end %>
</div>

You can do it responding to a javascript request when form is submitted.
Controller:
# app/controllers/mycontroller.rb
def create
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.user_id = current_user.id
#order.save
session[:order_id] = #order.id
respond_to do |format|
format.js { flash[:notice] = "Created order" }
end
end
And then create a view to show the message:
# app/mycontroller/create.js.erb
<% flash.each do |key, value| %>
$('.add-to-cart').append('<%= j content_tag :div, value, class: "flash #{key}" %>')
<% end %>
It should work!

You can use bootstrap alert to achieve it.
Controller:
def create
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.user_id = current_user.id
if #order.save
flash[:success] = "Successfully Submitted"
end
session[:order_id] = #order.id
end
You can display that flash message wherever you want to using this
View:
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>

Related

How to display validation error in rails using AJAX

I need to display the validation error of my post model. I have used AJAX call to create a post into the index page of the post. So that when the NewPost button is clicked it will display the new post form partial into the index page. While creating the post in index page if there is any validation errors found, the errors are displayed and it renders the new post form partial in js format again so that the new post form appears twice along with the validation error.
Posts controller:
def create
#post = #topic.posts.build(post_params)
#post.user = current_user
respond_to do |format|
if #post.save
# Success
else
format.js { render 'posts/new' }
end
end
end
Create.js.erb file:
alert("Post created Successfully");
$('.new_post').hide();
$('.new_one').show();
$('.post_div').prepend('<%= j render #post %>');
Index.html.erb file:
<div class="container" >
<% if params[:topic_id].present? %>
<h2 align="center"><span class="em-text"><%= #topic.topicname %> Posts</span></h2><hr>
<%= link_to "New Post", new_topic_post_path, :class => 'btn btn-primary new_one' ,remote: true%> <br><br><br>
<% else %>
<h2 align="center"><span class="em-text">All Posts</span></h2><hr>
<% end %>
<div class="post_div">
<%= render #posts %>
</div>
<%= will_paginate #posts, renderer: BootstrapPagination::Rails %>
</div>
Post partial for new post form:
<%= form_for [#topic, #post],remote: true,html: {multipart: true}, url: topic_posts_path do |f| %>
<% if #post.errors.any? %>
<% #post.errors.full_messages.each do |msg| %>
<div class="alert alert-danger"><%= msg %></div>
<% end %>
<% end %>
<div class="form-group">
<%= f.label "Title" %><br/>
<%= f.text_field(:title,{:class => 'form-control', :placeholder => 'Enter the Title'}) %>
</div>
<div class="form-group">
<%= f.label "Body" %><br/>
<%= f.text_area(:body, {:class => 'form-control', :placeholder => 'Enter the Post Body'}) %>
</div>
<div class="form-group">
<%= f.submit({:class => 'btn btn-primary'})%>
</div>
<% end %>
new.js.erb file:
$('.new_one').hide().after("<%= j render 'form' %>")
Use can like this
<% if #post.errors.any? %>
alert("ERROR(S):\n<%= j #post.errors.full_messages.join("\n") %>")
Check the post whether it has any errors if error exists alert the error else do something

rails4 js response XSS

I have a rails4 app. If I submit <script>alert('haha')</script> in the form then alert gets displayed, so it doesn't escape js (despite of having <%= j render #post %>), so my app is not protected from XSS.
Why is this happening? What should I do?
controller
def create
#post = current_user.posts.new(post_params)
#post_comment = PostComment.new
if #post.save
respond_to do |format|
format.html { redirect_to #post, notice: "Post saved!" }
format.js
end
else
.......
_form
<%= form_for #post, remote: true, method: :post, class: "post-create-form" do |f| %>
<div class="alert alert-danger" style="display:none">
<ul class="errors" style="display:none">
<%= render 'layouts/error_messages', object: f.object %>
</ul>
</div>
<div class="form-group">
<%= f.text_area :body, placeholder: "Share something useful..", class: "form-control post-create-body" %>
</div>
<div class="form-group">
<%= f.button "Share", class: "btn btn-primary btn-create-post", data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Saving..."} %>
</div>
create.js.erb
$("ul.errors").html("");
<% if #post.errors.any? %>
$('.alert-danger').show();
$('ul.errors').show();
<% #post.errors.full_messages.each do |message| %>
$("ul.errors").append($("<li />").html("<%= message.html_safe %>"));
<% end %>
<% else %>
$('ul.errors').hide();
$('.alert-danger').hide();
$('.post-index').prepend('<%= j render #post %>');
$('.post-create-body').val('');
$('.btn-create-post').prop('disabled',true);
<% end %>

Create.js.erb Javascript asking for partial

I'm trying to get my my create action to work in my rails app. When I have these two lines
$('#pit_form').remove(); //remove form
$('#new_link').show(); //show new link again
it functions properly, and removes the form plus adds the link back, but I can't show the new pit with my escape. I've tried a few things but it always gives me this error
ActionView::Template::Error (Missing partial pits/_pit with {:locale=>[:en], :formats=>[:js, :html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee]}. Searched in:
* "/Users/markhustad/projects/fire_2/app/views"
* "/usr/local/rvm/gems/ruby-2.1.1/gems/devise-3.2.4/app/views"
):
1: $('#pit_form').remove(); //remove form
2: $('#new_link').show(); //show new link again
3: $('#pit_index').append(<%= j (render(#pit)) %>);
app/views/pits/create.js.erb:3:in `_app_views_pits_create_js_erb___3365989432298988625_2214355520'
app/controllers/pits_controller.rb:20:in `create'
when I add this line or something similar(not sure why I need _pit partial)
$('#pit_index').append(<%= j (render(#pit)) %>);
My pits controller currently
class PitsController < ApplicationController
before_action :current_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def new
#pit = Pit.new
end
def index
#pit = Pit.all
#user = User.find_by(params[:id])
#pits = Pit.paginate(:page => params[:page]).order('created_at DESC').group_by { |pit| pit.created_at.strftime("%B %Y") }
end
def create
#pit = current_user.pits.create(pit_params)
respond_to do |format|
format.html { redirect_to pits_path}
format.js
end
end
def show
#pit = Pit.find(params[:id])
end
def edit
end
def update
#pit = Pit.find(pit_params[:id])
if #pit.update_attributes(pit_params)
redirect_to #pit
end
end
def destroy
#pit = Pit.find(params[:id])
#pit.destroy
end
def upvote
#pit = Pit.find(params[:pit_id])
#pit.upvote_from current_user
redirect_to pit_path(#pit)
end
def downvote
#pit = Pit.find(params[:pit_id])
#pit.downvote_from current_user
redirect_to pit_path(#pit)
end
private
def correct_user
#pit = current_user.pits.find_by_id(params[:id])
redirect_to root_path if #pit.nil?
end
def pit_params
params.require(:pit).permit(:topic, :summary, :image, :video_url, :author, :user_id)
end
end
Pits index
<div class = "container list-pits">
<%= link_to "Add New Pit", new_pit_path, id: "new_link", remote: true, class: "btn btn-default" %>
<br>
<br>
<% #pit.each do |pit| %>
<div class = "container">
<div class = "well", id = "pit_index">
<h3 id="pit-title"><%= link_to pit.topic, pit_path(pit) %></h3>
<p>by <%= link_to pit.author, '#' %></p>
<br>
<p><%= pit.summary %></p>
<p>Replies (<%= pit.comments.count %>)</p>
<br>
<p>Pit Created by: <%= link_to pit.user.name, pit.user %> on <%= pit.created_at %></p>
<%= link_to "View Pit", pit_path(pit), class: "btn btn-primary" %>
<%= link_to "Delete Pit", pit_path(pit), remote: true, method: :delete, data: { confirm: 'Are you sure?' } %>
</div>
</div>
<% end %>
</div>
_form in Pits
<div class="container new-pit">
<%= render 'devise/shared/error_messages', obj: #pit %>
<%= form_for #pit, remote: true, :html => {:multipart => true} do |f| %>
<div class = "form-horizontal", id = "pit_form">
<div class="form-group">
<%= f.label :topic, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_field :topic, class: "form-control", autofocus: true %>
</div>
</div>
<div class="form-group">
<%= f.label :author, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_field :author, class: "form-control", :placeholder => "Enter name of book author, lecturer, or presenter" %>
</div>
</div>
<div class="form-group">
<%= f.label :summary, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_area :summary, class: "form-control", :placeholder => "Present an argument for or against the material presented and state why you think it is accurate or not" %>
</div>
</div>
<div class="form-group">
<%= f.label :image, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.file_field :image, class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label :video, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_field :video_url, class: "form-control", :placeholder => "example: //www.youtube.com/embed/hBHYdK9xtYs (video is optional)" %>
<p class = "youtube-instruction">Must use the shared -> embed option</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6">
<%= f.submit "Start Pit", class: "btn btn-primary" %>
</div>
</div>
</div>
</div>
</div>
<% end %>
I know I'm close here but need a bit more direction. Thanks.
You need two things. First, a pit.js.erb file that has:
$('#pit_form').remove();
$('#new_link').show();
$('#pit_index').append(<%= j (render(#pit)) %>);
I think you already have this.
You also need a _pit.html.erb file under the /pits folder that describes the layout of individual pit items on the pit index.
The order of operations goes like this:
Send a create request via Ajax. On forms, this is typically done with the remote: true option, which uses Unobstrusive JavaScript.
Process the response in the controller's create action using format.js. By default, this renders the .js.erb file that corresponds to the action name (i.e. create.js.erb).
Inside this js.erb file, you can also embed more render commands. In your specific case, you are trying to render a _pit.html.erb or a _pit.js.erb template, both of which are missing.
If you already have the pit template in a specific folder, you can specify it in the render action, like this:
$('#pit_index').append("<%= j (render 'myfolder/pit') %>");
I hope this helps.

How to Create Nested Forms in Rails 4

I'm trying to let a user create Exercises with Equipment and Muscles in many-to-many relationships through their respective join tables( exercise_equipment, exercise_muscles ). I've gotten the form working for adding one equipment/muscle per exercise, but cannot figure out how to add a link to add another field to the form on the fly.
I've checked out RailsCasts, this post, have asked it as a side question on a previous post of my own, but simply cannot get this functionality to work. I'm fairly new to Rails 4 and am still trying to learn Javascript, but I'd love a thorough explanation of how to set this up the Rails 4 way!
My Models:
# id :integer
# name :string
# is_public :boolean
Exercise
has_many :exercise_equipment
has_many :equipment, :through => :exercise_equipment
accepts_nested_attributes_for :exercise_equipment
# id :integer
# exercise_id :integer
# equipment_id :integer
# optional :boolean
ExerciseEquipment
belongs_to :exercise
belongs_to :equipment
accepts_nested_attributes_for :equipment
# id :integer
# name :string
Equipment
has_many :exercise_equipment
has_many :exercises, :through => :exercise_equipment
My Controller Methods:
def new
#exercise = Exercise.new
#exercise.exercise_equipment.build
#exercise.exercise_muscles.build
end
def create
exercise = current_user.exercises.new( exercise_params )
if exercise.save!
redirect_to exercise
else
render 'new'
end
end
views/exercises/new.html.erb
<h1>Create New Exercise</h1>
<%= form_for #exercise do |f| %>
<%= render 'form', f: f %>
<%= f.submit "New Exercise" %>
<% end %>
views/exercises/_form.html.erb
<%= f.label :name %><br />
<%= f.text_field :name, autofocus: true %>
<%= f.check_box :is_public %> Public
<%= f.fields_for :exercise_muscles do |emf| %>
<%= emf.collection_select :muscle_id, Muscle.all, :id, :name, { include_hidden: false } %>
<% end %>
<%= f.fields_for :exercise_equipment do |eef| %>
<%= eef.collection_select :equipment_id, Equipment.all, :id, :name, { include_hidden: false } %>
<%= eef.check_box :optional %> Optional
<% end %>
Ajax
Cannot figure out how to add a link to add another field to the form
on the fly
The "Rails way" of doing that is to "pull" a new instance of the fields_for block from an ajax request.
The reason why Ajax is recommended is because it's the "Rails way" to do it - completely modular & extensible:
#config/routes.rb
resources :exercises do
get :add_field, on: :collection
end
#app/models/exercise.rb
Class Exercise < ActiveRecord::Base
...
def self.build #-> allows you to call a single method
exercise = self.new
exercise.exercise_equipment.build
exercise.exercise_muscles.build
return
end
end
#app/controllers/exercises_controller.rb
Class ExercisesController < ApplicationController
def add_field
#exercise = Exercise.build
respond_to do |format|
format.html
format.js
end
end
end
#app/views/exercises/new.html.erb
<%= form_for #exercise do |f| %>
<%= render "fields", locals: { f: f } %>
<%= f.submit %>
<% end %>
#app/views/exercises/add_field.js.erb
$("#form_element").append("<%=j render "exercises/form", locals: { exercise: #exercise } %>");
#app/views/exercises/_form.html.erb
<%= form_for exercise do |f| %>
<%= render "fields", locals: { f: f } %>
<% end %>
#app/views/exercises/_fields.html.erb
<%= f.fields_for :exercise_muscles, child_index: Time.now.to_i do |emf| %>
<%= emf.collection_select :muscle_id, Muscle.all, :id, :name, { include_hidden: false } %>
<% end %>
<%= link_to "New Field", exercises_add_fields_path, remote: :true %>
<%= f.fields_for :exercise_equipment, child_index: Time.now.to_i do |eef| %>
<%= eef.collection_select :equipment_id, Equipment.all, :id, :name, { include_hidden: false } %>
<%= eef.check_box :optional %> Optional
<% end %>
<%= link_to "New Field", exercises_add_fields_path, remote: :true %>
This will give you the ability to create the fields through an ajax call; which is the correct way to do it
After attempting to use Rich's solution, I wanted to find one that was a bit more minimal in terms of the code used. I found the gem Cocoon, which works great and was very simple to integrate.
My main _form view:
<div class="form-group">
<%= f.label :name %><br />
<%= f.text_field :name, autofocus: true %>
</div>
<div class="form-group">
<%= f.check_box :is_public %> Public
</div>
<div class="form-group">
<%= f.fields_for :exercise_muscles do |emf| %>
<%= render 'exercise_muscle_fields', :f => emf %>
<% end %>
<%= link_to_add_association 'Add Muscle', f, :exercise_muscles %>
</div>
<div class="form-group">
<%= f.fields_for :exercise_equipment do |eef| %>
<%= render 'exercise_equipment_fields', :f => eef %>
<% end %>
<%= link_to_add_association 'Add Equipment', f, :exercise_equipment %>
</div>
As can be seen here, the addition of a simple "link_to_add_association" method takes care of all of the Javascript in the background. For future readers, here are the partials that each of these form-groups contain:
_exercise_muscle_fields:
<%= f.collection_select :muscle_id, Muscle.all.order( 'muscle_group_id ASC' ), :id, :name, { include_hidden: false } %>
_exercise_equipment_fields:
<%= f.collection_select :equipment_id, Equipment.all.order( 'name ASC' ), :id, :name, { include_hidden: false } %>
<%= f.check_box :optional %> Optional

Confirmation message - Javascript rails application

I'm a bit new to rails and I'm just trying to display a confirmation message when a "Proposition" (created model) has been inserted. For this, I'm using a javascript functionality embedded to rails.
Unfortunately, when I click and submission button, the proposition is correctly inserted but I can't find a way to display this confirmation message (like "proposition correctly submitted" for example)...
Below the code that I'm using :
Proposition Model :
class Proposition < ActiveRecord::Base
belongs_to :ad
attr_accessible :email, :name, :phone, :price
validates_presence_of :name or :price or :email or :phone
end
Create method in controller :
def create
#ad = Ad.find(params[:ad_id])
#proposition = #ad.propositions.create(params[:proposition])
respond_to do |format|
if #proposition.save
format.html { redirect_to ad_path(#ad), notice: 'Proposition was successfully created.' }
format.json { render json: ad_path(#ad), status: :created, location: #proposition }
format.js
else
format.html { render action: "new" }
format.json { render json: #proposition.errors, status: :unprocessable_entity }
format.js { render action: "new" }
end
end
end
_form.html.erb :
<%= form_for [#ad, #ad.propositions.build], :remote => true do |f| %>
<% if #proposition.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#proposition.errors.count, "error") %> prohibited this proposition from being saved:</h2>
<ul>
<% #proposition.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :Prénom %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :"Adresse mail" %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :Téléphone %><br />
<%= f.text_field :phone %>
</div>
<div class="field">
<%= f.label :"Prix proposé" %><br />
<%= f.text_field :price %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
create.js.erb :
$('#new_proposition').fadeOut(1000);
new.js.erb :
$('#new_proposition_link').hide().after('<%= j render("form") %>');
Thanks for your help !
Since you already have a create.js.erb file, you can use JS to display an alert message or insert a confirmation message into the page like so,
# app/views/.../create.js.erb
$('#new_proposition').before('<p>Proposition correctly submitted!</p>');
$('#new_proposition').fadeOut(1000);
This inserts the <p>Proposition correctly submitted!</p> before the #new_proposition element. You may want to insert it somewhere else since this element will disappear.

Categories