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 %>
Related
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
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 %>
Although I'd like to add link_to_add with using simple_nested_form_for, the following error was displayed.
ArgumentError (Invalid association. Make sure that accepts_nested_attributes_for is used for :events association.):
There are similar questions in stackoverflow, but it doesn't work for me. So I post this as a new question.
The error was appeared when I add f.link_to_add in _schedule_form.html.erb.
_schedule_form.html.erb
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
<br>
<%= f.label :departure_date %>
<div class="input-group date" id="datetimepicker">
<%= f.text_field :departure_date, class: 'form-control' %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<script type="text/javascript">
$(function () {
$('#datetimepicker').datetimepicker({format:'MMM-DD-YYYY'});
});
</script>
<br>
<div id="room">
<%= f.simple_fields_for :rooms do |a| %>
<p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p>
<div id="event">
<% a.simple_fields_for :events do |e| %>
<%= e.input :from %>
<% end %>
</div>
#add here!!!
<%= f.link_to_add "Add event", :events, data: {target: '#event'}, class: "btn btn-primary" %>
<%= a.input :room %>
<% end %>
</div>
new_html.erb
<div class="row">
<div class="col-md-12">
<p>Create schedule</p>
<%= simple_nested_form_for(#schedule) do |f| %>
<%= render 'schedule_form', f: f %>
<%= f.submit "Create my schedule", class: "btn btn-primary" %>
<br>
<% end %>
</div>
</div>
Give the following models:
class Schedule < ActiveRecord::Base
belongs_to :user
has_many :rooms
accepts_nested_attributes_for :rooms, allow_destroy: true
...
class Room < ActiveRecord::Base
belongs_to :schedule
has_many :events
accepts_nested_attributes_for :events, allow_destroy: true
...
class Event < ActiveRecord::Base
belongs_to :room
...
schedule_controller.rb
class SchedulesController < ApplicationController
...
before_action :set_schedule, only: %i(show edit update destroy)
...
def new
#schedule = Schedule.new
room = #schedule.rooms.build
room.events.build
end
def create
#schedule = current_user.schedules.build(schedule_params)
if #schedule.save
flash[:success] = "schedule created!"
redirect_to root_url
else
render 'new'
end
end
def edit
#day_max = Room.where("schedule_id = ?", #schedule.id).maximum(:day)
end
def update
#schedule.rooms.maximum(:day)
if #schedule.update(schedule_params)
flash[:success] = "schedule updated!"
redirect_to root_url
else
render 'edit'
end
end
private
def schedule_params
params.require(:schedule).permit(:title, :departure_date, rooms_attributes: [:id, :_destroy, :room, :day, events_attributes: [:id, :_destroy, :from, :to, :title, :detail]])
end
def set_schedule
#schedule = Schedule.find(params[:id])
end
No error have been displayed before adding link_to_add.
It would be appreciated if you could give me any suggestion.
SOLVED!!!
<div id="room">
<%= f.simple_fields_for :rooms do |a| %>
<div id="room_<%= a.object.object_id %>">
<p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p>
<%= a.simple_fields_for :events do |e| %>
<span class="form-inline">
<%= e.input :from, label: false %>
<%= e.input :to, label: false%>
</span>
<%= e.input :title, label: 'event' %>
<% end %>
</div>
<%= a.link_to_add "Add event", :events, data: {target: "#room_#{a.object.object_id}"}, class: "btn btn-primary" %>
<%= a.input :room %>
<% end %>
</div>
div#room should be something like :
<div id="room">
<%= f.simple_fields_for :rooms do |a| %>
<p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p>
<% a.simple_fields_for :events do |e| %>
<div id="event">
<%= e.input :from %>
</div>
<% end %>
#add here!!!
<%= a.link_to_add "Add event", :events, data: {target: '#event'}, class: "btn btn-primary" %>
<%= a.input :room %>
<% end %>
</div>
First of all nested_form gem is abandoned, so I would suggest to use cocoon which is up to date now
Also probably you attributes filtered
room_attributes: [..., events_attributes: [...]]
As your attributes for rooms should be in plural form rooms_attributes
And the last suggestion do not use multi nesting. Try to have a look on form objects pattern
Hope it helps
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.
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.