CODE:
login.ejs
<script>
req.flash('success_msg', 'You have logged in');
</script>
header.ejs
<div class = "alertMessage">
<% if (success_msg != false){ %>
<span class="alert alert-success containerMargins">
<%= success_msg %>
</span>
<% } %>
<% if (error_msg != false){ %>
<span class="alert alert-danger containerMargins">
<%= error_msg %>
</span>
<% } %>
</div>
SITUATION:
This has nothing to do with using flash on the server-side and displaying the message on the client-side: it already works perfectly for me.
This has to do with calling flash from the client or replicating the same behaviour from the client with some other library.
QUESTION:
The code I showed of course does not work on the client-side, what can I do to replicate that behaviour on the client-side ?
The flash is a special area of the session used for storing messages. Messages are written to the flash and cleared after being displayed to the user. The flash is typically used in combination with redirects, ensuring that the message is available to the next page that is to be rendered.
So you need code which:
Stores some data somewhere that the client can access between pages
Reads that data
Deletes it after being read
Start by picking somewhere for option 1 (such as localStorage, or a cookie). The rest should be trivial - the original module is about 80 lines of code, including about 50% comments — to implement (but specific to which choice you make).
Here is the solution I used:
<div class = "alertMessage">
<span class="alert alert-success containerMargins" id="successDiv"></span>
<span class="alert alert-danger containerMargins" id="errorDiv"></span>
</div>
<script>
if (localStorage.getItem("success_msg_local") != null) {
document.getElementById("successDiv").innerText = localStorage.getItem("success_msg_local");
document.getElementById("successDiv").style.display = "inline-block";
window.localStorage.clear();
}
else if (localStorage.getItem("error_msg_local") != null) {
document.getElementById("errorDiv").innerText = localStorage.getItem("error_msg_local");
document.getElementById("errorDiv").style.display = "inline-block";
window.localStorage.clear();
}
</script>
and replacing req.flash('success_msg_local', 'You have logged in') by:
localStorage.setItem('success_msg_local', 'You have logged in');
Related
In my registration form I have some validation logic which works perfectly fine in Chrome but in Safari error message don't disappear below form after filling empty fields. It looks like show() and hide() doesn't work and I don't now why because based on this https://www.quirksmode.org/dom/events/index.html it should worked.
if (registrationsForm.length > 0) {
var emailField = $('#users-registrations-email');
var emailConfirmationField = $('#users-registrations-email-confirmation');
var emailInvalidMsg = $('.bank-employees-users-registration__registrations__not-identical-email');
var obligatoryInvalidMsg = $('.bank-employees-users-registration__registrations__email--invalid');
submit.on('click', function(e) {
e.preventDefault();
if (emailField.val() !== emailConfirmationField.val() && emailField.length > 0) {
emailInvalidMsg.show();
emailField.addClass("invalid");
emailConfirmationField.addClass("invalid");
emailConfirmationField[0].setCustomValidity('Incorrect confirmation email');
if (emailField.val() !== '') obligatoryInvalidMsg.hide();
} else {
emailConfirmationField[0].setCustomValidity('');
}
validateEmail();
var invalidInput = $('input:invalid');
if (invalidInput.length === 0 && !fileInput.hasClass('invalid')) {
form.submit();
} else {
invalidInput.addClass('invalid');
validateInput();
}
});
}
Function which is responsible for input validation:
function validateInput() {
$('input').change(function() {
if ($(this).is(':valid')) {
$(this).removeClass('invalid');
}
});
}
Edit
This is a code snippet from view
new.html.erb
<div class="floating-label bank-employees-users-registration__registrations-input--wrapper">
<%= f.email_field :email, class: "bank-employees-users-registration__registrations-input floating-field", id: "users-registrations-email", placeholder: t('.email'), required: true, aria_required: true %>
<%= f.label :email, t('.email'), class: "floating-label-placeholder" %>
<span class="bank-employees-users-registration__registrations__not-identical-email">
<%= t('.email_not_identical') %>
</span>
<span
class="bank-employees-users-registration__registrations-input--invalid-msg bank-employees-users-registration__registrations__email--invalid"
id="bank-employees-users-registration__registrations__email--invalid">
<%= t'.obligatory' %></span>
<% if #registration_form.errors.full_messages_for(:email).first %>
<div class="alert alert-danger">
<div class="error-explanation">
<%= t('activerecord.errors.models.user.attributes.email.taken') %>
</div>
</div>
<% end %>
</div>
Edit2
Maybe this will be helpful - as you see there are some email validations where two email address has to be equal. When I provide different email address it shows me error message that they are not equal but if I correct them, the error will be changed to - this field is required. I was trying to implement this solution jquery .show() and .hide() not working in safari - adding spinner to <a href but without any positive results.
Why not get rid of all that and use HTML5 fields? They have client-side validations that work across browsers and you can validate input on the server side using model validations, let Rails deal with all that.
I know it may be a bit of upfront investment into refactoring all that but otherwise things will only get worse in the long term if you keep doing what you're doing.
Also look at the Bootstrap form gem in case you're using Bootstrap.
The flash message only works on my local machine during development...It doesn't work when I deployed the app on Heroku. I've been trying to find the answer but couldn't find anything that solves my problem.
api/policies/flash.js
module.exports = function(req, res, next) {
res.locals.flash = {};
if(!req.session.flash) return next();
res.locals.flash = _.clone(req.session.flash);
// clear flash
req.session.flash = {};
next();
};
api/controller/UserController.js (within create action) - When the form is submitted successfully, redirect to the homepage and display thank you message.
res.redirect("/");
req.flash('signup-message', '<div class="thankyou-message-wrapper bg-success"><span class="glyphicon glyphicon-remove pull-right" aria-hidden="true"></span><span class="thankyou-message">Thank you for submitting the form!<br> Our administer will review your submission and publish soon.</span></div>');
view/main/index.ejs - This is how I render the message from the UserController.js
<%- req.flash('signup-message') %>
Does anyone have any insight as to why the flash message is not showing up when I deployed on Heroku?
You will need to add the policy to the routes.js file to enable a policy for the homepage.
For example:
'/': {
view: 'homepage', policy: 'flash'
}
Then in your UserController, add your message to session.flash:
req.session.flash = {
message : '<div class="thankyou-message-wrapper bg-success"><span class="glyphicon glyphicon-remove pull-right" aria-hidden="true"></span><span class="thankyou-message">Thank you for submitting the form!<br> Our administer will review your submission and publish soon.</span></div>'
}
Finally, display the message in your homepage, first check if a message exists and then display:
<% if(flash && flash.message) { %>
<%- flash.message %>
<% } %>
How can I validate credit card informations on the client side without passing any info to my server (PCI compliance) ?
The API that I using respond my request with a token, the only info that I need to store on my database. I send the credit card infos for them, and they respond with a token.
I already have the methods to validate the credit card via javascript and make an API call, javascript too, but the info are passing in my server, as I can see on server log:
Started POST "/api_checkout" for 127.0.0.1 at 2014-08-04 21:53:02 -0300
Processing by Marketplace::CheckoutController#api_buy as JS
Parameters: {"utf8"=>"✓", "number"=>"4111 1111 1111 1111", "verification_value"=>"123", "full_name"=>"Test user", "expiration"=>"14/15", "token"=>"B5E7A1F1-9822-4433-9FEE-30B625B8B070"}
Rendered marketplace/checkout/api_buy.js.erb (0.4ms)
Completed 200 OK in 43ms (Views: 39.2ms | ActiveRecord: 0.0ms | Solr: 0.0ms)
Started POST "/api_checkout" for 127.0.0.1 at 2014-08-04 21:53:03 -0300
Processing by Marketplace::CheckoutController#api_buy as HTML
Parameters: {"utf8"=>"✓", "number"=>"4111 1111 1111 1111", "verification_value"=>"123", "full_name"=>"Test user", "expiration"=>"14/15", "token"=>"B5E7A1F1-9822-4433-9FEE-30B625B8B070"}
Completed 500 Internal Server Error in 21ms (no problem here, didn`t made the view yet)
I dont know if I`m doing the right things, but here what I have today
Here is my form:
<%= form_tag api_buy_path,:method => :post, :id => 'payment-form', :remote => true do %>
<div class="usable-creditcard-form">
<div class="wrapper">
<div class="input-group nmb_a">
<div class="icon ccic-brand"></div>
<%= text_field_tag :number, params[:number], :class=>"credit_card_number", :"data-api"=>"number" %>
</div>
<div class="input-group nmb_b">
<div class="icon ccic-cvv"></div>
<%= text_field_tag :verification_value, params[:verification_value], :class=>"credit_card_cvv", :"data-api"=>"verification_value" %>
</div>
<div class="input-group nmb_c">
<div class="icon ccic-name"></div>
<%= text_field_tag :full_name, params[:full_name], :class=>"credit_card_name", :"data-api"=>"full_name" %>
</div>
<div class="input-group nmb_d">
<div class="icon ccic-exp"></div>
<%= text_field_tag :expiration, params[:expiration], :class=>"credit_card_expiration", :"data-api"=>"expiration" %>
</div>
</div>
</div>
<div class="token-area">
<%= label_tag :token, "Card token:"%>
<%= text_field_tag :token, params[:token],:id=>"token", :readonly=> true, :value=>""%>
</div>
<%= submit_tag 'Submit' %>
<% end %>
Here is the javascript that I`m using:
SomeAPI.setAccountID("some-id");
SomeAPI.setTestMode(true);
jQuery(function($) {
$('#payment-form').submit(function(evt) {
var form = $(this);
var cardNumber = document.getElementById("number").value;
//Check with the number is valid
if(SomeAPI.utils.validateCreditCardNumber(cardNumber)){
var brand = SomeAPI.utils.getBrandByCreditCardNumber(cardNumber);
var cvv = document.getElementById("verification_value").value;
//Check the CVV by brand
if(SomeAPI.utils.validateCVV(cvv, brand)){
var expiration = document.getElementById("expiration").value.split("/");
var expiration_year = expiration[1];
var expiration_month = expiration[0];
//Check the Expiration Date
if(SomeAPI.utils.validateExpiration(expiration_month, expiration_year)){
var name = document.getElementById("full_name").value.split(" ");
var firstName = name[0];
var lastName = name[name.length - 1];
//Check everything
cc = SomeAPI.CreditCard(cardNumber, expiration_month, expiration_year, firstName, lastName, cvv);
var tokenResponseHandler = function(data) {
if (data.errors) {
//console.log(data.errors);
alert("Error: " + JSON.stringify(data.errors));
}
else {
$("#token").val( data.id );
form.get(0).submit();
}
// Send the form
form.trigger("submit.rails");
}
SomeAPI.createPaymentToken(cc, tokenResponseHandler);
return true;
}else{
alert("Invalid")
return false;
}
}else{
alert("Invalid")
return false;
}
}else{
alert("Invalid")
return false
}
});
});
The issue is you need to clear out the sensitive form data before calling form.submit:
$("#token").val( data.id );
form.get(0).submit();
The form needs the sensitive credit card data to perform the validation, however your Rails app does not need this data - it only needs the token.
I typically set the card number to a string containing just the last four digits of the card number like: ** ** **** 1234
Your SomeAPI may already be returning a masked CC back to you, otherwise you'll need to do it via Javascript.
Sorry i couldn't get a better title to my question but hope my explanation will give you guys a better idea of what's going on?
I have a model Airport and three other models West East and South that aren't related in anyway only that Airport model needs some of the other fields like this form shows.
<%= form_for(#airport) do %>
<%= f.collection_select(:airport_name, AirPortManager.all, etc...) %>
//AirPortManager is a collection of available airports
<div class="west-airports" style="display:none;">
<%= f.collection_select(:airline_name, WestAirlineManager.all, ....) %>
</div>
<div class="east-airports" style="display: none;">
<%= f.collection_select(:airline_name, EastAirlineManager.all, ....) %>
</div>
<div class="south-airports" style="display: none;">
<%= f.collection_select(:airline_name, EastAirlineManager.all, ....) %>
</div>
<% end %>
The airport model validates :airline_name, :presence => true . Now the problem is with
my javascript. If a user selects airport west in AirPortManager.all the west-airports div` should be shown and so on. But my validation method airport keeps throwing a required field error for :airline_name and if not that it keeps a value from a previous selection. How can i pass the visible div value to airport parameters or if i select an empty value the previous value shoudn't remain constant. Below is my javascript and hope my question makes sense.
<script type="text/javascript">
$(document).ready(function() {
$("#aiport_manager_aiport_name").change(function(){
var value = this.value;
if (value == "West") {
$('.west-aiports').show();
$('.east-airports').attr("disabled", true);
$('.east-airports').hide();
$('.south-airports').attr("disabled", true);
$('.south-airports').hide();
}
else if (value == "East") {
$('.east-airports').show();
$('.west-aports').hide();
$('.west-airports').attr("disabled", true);
$('.south-airports').hide();
$('.south-airports').attr("disabled", true);
}
else if (value == "South") {
$('.south-aiports').show();
$('.west-airports').hide();
$('.west-airports').attr("disabled", true);
$('.east-airports').hide();
$('.east-airports').attr("disabled", true);
}
});
});
</script>
I try and disable the other collection_selects in their respective divs but still get a validation error or get a persistent value.
Your form has multiple elements with the same name (:airline_name), which is the core problem. You're on the right track with disabling, but you're disabling the div instead of the select. I would just do this:
// before form is submitted, disable all hidden selects
$('form').on('submit', function(e) {
$('select:hidden').prop('disabled', true);
});
Tried doing http://davidwparker.com/2008/09/17/site-wide-announcements-in-rails-using-jquery-jgrowl/
Am really bad with JS. Think I am messing up on the last part where it says "This code goes in your application.js file (somewhere in $(function){ //here })"
Am I not suppose to do a link_to_function and create a function with this code that references that link?
Really lost on this one.
Updated -
application.js looks like
$(document).ready(function() {
$.jGrowl.defaults.closer = true;
$("#announcements_box").css("display", "none");
$("#announcements_box .announcement").each(function(){
$jQuery.jGrowl(this.textContent,{ sticky:true, close:function(e,m,o){hide_announcements();} });
});
});
function hide_announcements(){
$.get(
'/hide_announcements'
);
$("#announcements_box").fadeOut();
return false;
}
And my application.html.erb has
<% unless current_announcements.empty? %>
<div id="announcements_box">
<% for announcement in current_announcements %>
<div id="announcement_<%= announcement.id.to_s %>" class="jGrowl">
<%= announcement.message %>
<%= link_to "Hide Annoucements", hide_announcements_path, :id => 'hideAnn'%>
</div>
<% end %>
</div>
<% end %>
I'm not sure what $(function){ //here } notation means, that should give you error in the browser, but I think he just wants to execute code after page is loaded:
$(document).ready(function() {
// here
}
And the culprit was I only entered a div ID when I needed to have a div ID and class.