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.
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 have a Resume model and an Education model. Education belongs_to resume and resume has_many educations.
I'm currently using a form in Resume's show.html.erb view to enter data for educations just to make sure it works.
In my routes.rb file I have:
resources :resumes do
resources :educations
end
In my educations_controller.rb file I have this:
def create
#resume = Resume.find(params[:resume_id])
#education = #resume.educations.build(education_params)
respond_to do |format|
if #education.save
format.html { redirect_to #resume, notice: 'Education was successfully created.' }
format.json { render :show, status: :created, location: #education }
else
format.html { render :new }
format.json { render json: #education.errors, status: :unprocessable_entity }
end
end
end
This allows me, in my views/resumes/show.html.erbto have the following:
<%= form_for [#resume,Education.new] do |f| %>
<div class="field">
<%= f.label :sectionTitle %><br>
<%= f.text_field :sectionTitle %>
</div>
<div class="field">
<%= f.label :completed %><br>
<%= f.date_select :completed %>
</div>
<div class="field">
<%= f.label :degree %><br>
<%= f.text_field :degree %>
</div>
<div class="field">
<%= f.label :school %><br>
<%= f.text_field :school %>
</div>
<div class="field">
<%= f.label :summary %><br>
<%= f.text_area :summary %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This is currently working and allows me to enter multiple educations per Resume.
The issue is, I first have to create the resume entry before creating an education entry because the education entry depends on the resume_id integer.
How can I re structure my code so that I can create multiple education entries for a specific resume that doesn't yet have an ID so that essentially, on submit the resume is assigned an ID then any subsequent educations are attached to the given resume_id and given their own education ID?
I suspect I'll probably have to use javascript which is fine, but even so, I'm not sure what to do once intercept the default form action.
This is just little example but it works totally fine.
In routes.rb
post 'add_resume_education' => 'resumes#twince'
In resumes_controller.rb, in your case. Use your own MODEL like resume and education and change passing params too.
def twince
resume = Resume.create!(title: params[:data][:category_title])
post = resume.educations.create!(sectionTitle: params[:data][:educations][:sectionTitle])
redirect_to :back, notice: 'Yeah Created'
end
in HTML page:
<%= form_for :data, url: add_resume_education_path do |f| %>
<div class="field">
<%= f.label :category_title %>
<%= f.text_field :category_title %>
</div>
<br>
<div class="field">
<%= f.fields_for :educations do |edu| %>
<div class="field">
<%= edu.label :sectionTitle %><br>
<%= edu.text_field :sectionTitle %>
</div>
<% end %>
</div>
<br>
<%= f.submit 'create' %>
<% end %>
Also here quite good source, Nested Form
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 %>
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
I'm trying to figure out how to add and remove a group of fields in my Rails 3 app using Jquery. I got the jquery script to work with plain html, which you can see here: http://jsfiddle.net/beehive/ABvFH/1/
However, I can't figure out how to translate this to Rails 3. More specifically, what do I replace "formfield" with in the application.js file for this to work?
application.js
$(document).ready(function() {
$(function() {
var x = $('#uploadform');
var i = $('#uploadform ul').size() + 1;
$('#addmore').live('click', function() {
if ($(".item", x).length < 9) {
$('<ul class="item" class="field">formfield ' + i + ' Remove</p>').appendTo(x);
i++;
}
return false;
});
$('#remfields').live('click', function() {
if (i > 2) {
$(this).parents('ul').remove();
i--;
}
return false;
});
});
});
form.html.erb
<%= form_for(#upload) do |f| %>
<% if #upload.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#upload.errors.count, "error") %> prohibited this upload from being saved:</h2>
<ul>
<% #upload.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<h2>Add More Fields</h2>
<div id="uploadform">
<ul class="field">
<li>
<%= f.label :title %><br />
<%= f.text_field :title %>
</li>
<li>
<%= f.label :genre %><br />
<%= f.collection_select :genre, Upload::GENRES, :to_s, :to_s, :include_blank => true %>
</li>
<li>
<%= f.label :category %><br />
<%= f.collection_select :category, Upload::CATEGORIES, :to_s, :to_s, :include_blank => true %>
</li>
<li>
<%= f.label :age %><br />
<%= f.collection_select :age, Upload::AGES, :to_s, :to_s, :include_blank => true %>
</li>
</ul>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
All I had to do to get it to work is comment $(function() {
$(document).ready(function() {
//$(function() {
var x = $('#uploadform');
var i = $('#uploadform ul').size() + 1;
$('#addmore').live('click', function() {
if ($(".item", x).length < 9) {
$('<ul class="item" class="field">formfield ' + i + ' Remove</p>').appendTo(x);
i++;
}
return false;
});
$('#remfields').live('click', function() {
if (i > 2) {
$(this).parents('ul').remove();
i--;
}
return false;
});
//});
});
Edit:
What do you mean insert them?
To access the elements you can loop through them with
$('#uploadform > ul').each(function(index) {
alert(index + ': ' + $(this).text());
});
Notice your generated HTML. You are creating ul (unordered list) for each li (list item). you may want to fix that to only append list items.
I guess you want to allow user to add many uploads before submit form.
In that case I'm using rails nested attributes.
Here is example. Order has many Photos
Order model:
class Order < ActiveRecord::Base
has_many :photos, :dependent=>:destroy, :inverse_of=>:order
accepts_nested_attributes_for :photos, :allow_destroy=>true,:reject_if=> :all_blank
end
Photo model:
class Photo < ActiveRecord::Base
has_attached_file :photo
belongs_to :order
end
Order form view:
<%= form_for #order, :html => {:autocomplete => :off, :multipart => true} do |f| %>
<%= f.label :title %><br />
<%= f.text_field :title %>
<h3>Order photos</h3>
<%= f.fields_for :photos do |photo| %>
<%= render :partial=>'photo_form', :object=> photo, :as => :f %>
<% end %>
<%= link_to 'Add photo', new_photo_path, :remote=>true, :id=>'add_photo' %>
<%= f.submit%>
<% end %>
photo_form partial:
<fieldset class="photo" data-status="<%= f.object.persisted? ? 'db':'new' %>">
<% if f.object.persisted? %>
<div class="field">
<label>Photo:</label><br />
<%= link_to f.object.photo.url, :target=>'_blank' do %><%= image_tag f.object.photo.url(:mini) %><% end %>
</div>
<% else %>
<%= f.label :photo
<%= f.file_field :photo %>
<%= f.text_field :description %>
<%= f.check_box :_destroy, :class=>'delete' %>
</fieldset>
Now in your controller you need 3 actions to edit order with photos: edit, update, add_photo(ajax action when user click add photo link):
class OrdersController < ApplicationController
def edit
#order = Order.find(params[:id])
end
# Action responsible for updating existing order record
def update
#order = Order.find(params[:id])
if #order.update_attributes(params[:order])
redirect_to #order, :notice=>'Order updated'
else
render :action => "edit" #save error, display order form with errors
end
end
# Action responsible for creating nested form for order photo
def new_photo
#nothing just renders 'new_photo.js.erb'
end
end
new_photo.js.erb:
$object=$("<%= escape_javascript( render(:partial => "photo_form", :locals=>{
:f=>FormBuilder.new("order[photos_attributes][#{rand(400000)}]",Photo.new(),self,{},proc {})
}) ) %>").hide(); //generates new photo view
$object.insertBefore("a#add_photo").slideDown(500);
This is just example, but you shouldn't have problem to adopt this in your application.