Setting timezone on Rails from clientside using javascript - javascript

I have a webapp that sets timezone
post_controller.rb
before_filter :set_time_zone
def set_time_zone
Time.zone = user.time_zone
end
Now, instead of getting the time_zone from the user at registration, I was wondering how I'd set the timezone dynamically from the client side and set it in the before_filter.
I was trying to use detect_timezone_rails gem. The gem provides an easy way to access clientside timezone, simply by calling the function like this from js file.
$(document).ready(function(){
$('#your_input_id').set_timezone();
});
Now, the above code automatically sets your hiddenfield input or select input, but I was wondering if you could simply use the function call to save to session and retrieve it from Rails server. I guess when the user first visits the site, the timezone can be set and the session value can be used to set timezone for the rest of the visit. I'd think it'd be possible to use the session value to set timezone in the before filter. Being pretty new to javascript, I'm not sure how to access Rail's encrypted cookie store to set the value. Is this possible? if so, how can I do this?
thanks in advance,

#javascript
function readCookieValue(cookieName)
{
return (result = new RegExp('(?:^|; )' + encodeURIComponent(cookieName) + '=([^;]*)').exec(document.cookie)) ? decodeURIComponent(result[1]) : null;
}
$(document).ready(function(){
if(readCookieValue("time_zone") === null) {
$.post('/set_time_zone',
{ 'offset_minutes':(-1 * (new Date()).getTimezoneOffset())});
}
#controller:
def set_time_zone
offset_seconds = params[:offset_minutes].to_i * 60
#time_zone = ActiveSupport::TimeZone[offset_seconds]
#time_zone = ActiveSupport::TimeZone["UTC"] unless #time_zone
if #time_zone
cookies[:time_zone] = #time_zone.name if #time_zone
render :text => "success"
else
render :text => "error"
end
end

We did this somewhat differently. We use the gon gem to set a variable on the Rails side if we want to collect the timezone from JS. Then we have JS code on the client that examines that variable, and if set, does an XHR post to an endpoint (like the OP did) with the timezone string as returned by the jstimezonedetect script, which returns an IANA timezone key. Finally, to convert this to a Rails 3.2.19 timezone name, we did ActiveSupport::TimeZone::MAPPING.invert[iana_key]. It took a few steps to figure this out, hope it helps someone.

Related

Retrieve Timezone as variable from javascript to asp.net codebehind

Although this question may seem as a duplicate of other questions, it is not.
I have a basic asp.net web application and I simply want to retrieve client time. Here are the problems I encountered:
1- Using C# code DateTime.Now basically gives the dateTime of the place of the server. So obviously it is not useful.
2- Then, I tried to get the datetime from JavaScript (browser time). Past stackoverflow questions suggest that I should use a HiddenField. But it is useful as long as a button ignites a functions which would assign datetime value to a hiddenfield. I tried to assign the datetime value to hiddenfield with window.onload function (so that hiddenvalue can get datetime when the page loads). Another problem occured: according to asp.net page lifecycle, javascript code comes after the page_load event. So another fail.
3- Here is the ultimate solution I came up with:
First, I wrote a JS function that creates a cookie of the offset when called:
function createZoneCookie() {
var zone = new Date().getTimezoneOffset() / -60
var date = new Date();
date.setTime(date.getTime() + (30 * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toGMTString();
document.cookie = "clienttzone=" + zone + expires + "; path=/";
}
Then, I used the following code located in the codebehind(c#):
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Cookies["clienttzone"]==null)
{
ScriptManager.RegisterStartupScript(this,GetType(), "Javascript", "javascript:createZoneCookie(); ", true);
}
}
It works fine, but!! As you know user can access to my js function using the inspect (F12) button in their browser. Thus, they can alter my code and give a false dateTime or even worse create their own arbitrary cookies. And as I was told, it is impossible to make a JS code invisible to the user.
How the hell do people retrieve user timezone without compromising sensitive code?
PLUS Is there a way by which the server side code can use a client-side returning-function? Let me clarify:
ScriptManager.RegisterStartupScript(this,GetType(), "Javascript", "javascript:createZoneCookie(); ", true);
I have used the above code to run a function from the server side but as you know the createZoneCookie function is a void-type function.
My question is: can I get a value from a JS function from the C# side of my code?
this question didn't work because the accepted answer doesn't adress to the question of serverside-clientside value pass.

Inserting data from JS script into mysql database

I have created a script to count down whatever value I submit into a form and then output "the submitted value + the date of the moment I clicked on the submit button" as a result.
But now I want to store the result into my database every time I use the form by using SQL query and then echo all of these results in another page named "log.php" using SELECT SQL query.
var timelog = [];
function myF() {
countdown(s);
log = document.getElementById("log").innerHTML = s + 'at ' + new Date();
timelog.push(log);
}
function logged() {
document.getElementById("timeloggg").innerHTML = timelog;
}
I have tried to assign the result to a variable, but obviously, I cant use this variable outside of the script.
With some googling, I was told to use Ajax, but sadly I couldn't figure out how to insert the data using ajax, because all of the code examples out there are only about calling data from the database.
So any advice on how to insert the result into my database? I'm still a beginner so please explain in detail if you don't mind.
It is possible, of course, to insert data into your database from client side js, BUT DONT! I can't think of a way to do it that would not expose your database credentials, leaving you open to malicious actors.
What you need to do is set up a php script on your server, then send the data (either by POST or GET) you want inserted to that with an xhr request, and let that php script do the insert. HOWEVER, there is quite a bit to securing even that. Google "how to sanitize mysql inputs in php" and read several articles on it.
Depending on what you need to do, you can sanitize the inputs yourself, but the recommended way to do it is with prepared statements, which you will need to read the documentation for your specific implementation, whether it's mysqli or pdo in mySQL or some other library (say if you're using SQL, postGRE, Oracle, etc).
HTH
=================================================
Here is how to do it in js, BUT DONT DO THIS, unless you are never going to expose this code outside of your local computer.
var connection = new ActiveXObject("ADODB.Connection");
var connectionstring = "Provider=host;Data Source=table;User Id=user;Password=pass;";
connection.Open(connectionstring);
var rs = new ActiveXObject("ADODB.Recordset");
var sql = {{your sql statement}};
rs.Open(sql, connection);
connection.close;
==============================================
For php, do something like this, replacing host, user, pass, db with your actual credentials and hostname and database:
$db = new mysqli({host}, {user}, {pass}, {database});
if($db->connect_errno > 0){ die ("Unable to connect to database [{$db->connect_error}]"); }
to set the connection. If this is a publicly accessible php server, then there are rules about how to set up the connection so that you don't accidentally expose your credentials, but I'm going to skip that for now. You would basically save this into a file that's not accessible from the outside (above the document root, for instance) and then include it, but database security is a complex topic.
To get the values you passed in the query string of your ajax call:
$val1 = $_GET['val1'];
$val2 = $_GET['val2'];
Then to do the insert with a parameterized query:
$query = $db->prepare("
INSERT INTO your_table (field1, field2)
VALUES (?, ?)
");
$query->bind_param('ss', $val1, $val2);
$query->execute();
Now, here you're going to have to look at the documentation. 'ss' means that it's going to treat both of those values you're inserting as strings. I don't know the table set up, so you'll have to look up the right code for whatever you are actually inserting, like if they were integers, then 'ii', or 'si' would mean the first value was a string and the second one was an int.
Here are the allowed values:
i - integer
d - double
s - string
b - BLOB
but look at the documentation for prepared statements anyway. I used msqli in this example.
You might want to check Ajax requests.
I would suggest to start here.
What you will do is basically create asynchronous requests from javascript to a php file on your server.
Ajax allows web pages to be updated asynchronously by exchanging small
amounts of data with the server behind the scenes. This means that it
is possible to update parts of a web page, without reloading the whole
page.

Rails Live: Dynamically send resut from method to browser

I am trying to notify the browser of the user of a change of the status of the model. I am trying to use the live-module of Rails for that. Here is what I have got so far:
require 'json'
class Admin::NotificationsController < ActionController::Base
include ActionController::Live
def index
puts "sending message"
videos = Video.all
response.headers['Content-Type'] = 'text/event-stream'
begin
if(params[:id].present?)
response.stream.write(sse({id: params[:id]},{event: "video_encoded"}))
end
rescue IOError
ensure
response.stream.close
end
end
private
def sse(object, options = {})
(options.map{|k,v| "#{k}: #{v}" } << "data: #{JSON.dump object}").join("\n") + "\n\n"
end
end
The idea behind the above controller is, that when its url gets called with a parameter, it would send this parameter (in this case the id) to the user. Here is how I am trying to call the controller:
notifications_path(id: video.id)
Unfortunately though, the following event-listener in the browser does not fire, even if I use curl to provoke an event:
var source = new EventSource('/notifications');
source.addEventListener("video_encoded", function(event) {
console.log("message")
console.log(event)
});
The goal of this is, that I want to add an dom-element to a certain page (later on) if there is a change. There may be a better way, but Ruby Live seemed like a suitable solution. Any tips or proposals of a different approach are appreciated.
Your use case does not seem like a valid use case for ActionController::Live. You are not sending a streaming output to the browser. You do a one time check on ID and send the JSON output.
Use a regular controller and get the request by AJAX instead of EventSource.

How to store this data in cookies?

Let's say i have some textboxes/textareas of which the values have to be stored. The values have to be stored on key press, so that no data is lost when the user closes the page too early. Here's my current code (using cookies):
function createCookie(name, value, days) {
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
var expires = '; expires=' + date.toGMTString();
} else var expires = '';
document.cookie = name + '=' + value + expires + '; path=/';
}
$('input').keyup(function () {
var $this = $(this);
createCookie($this.attr('name'), $this.val(), 1);
});
jsFiddle
This works great.
With just 4 textboxes i see no problems but imagine having 50+ textboxes or textareas (not accounting usability/user experience). Will this cause any problems?
I'm open to any suggestions/alternatives
I'd opt for using local storage (see http://www.w3schools.com/html/html5_webstorage.asp), seems more scalable than setting a cookie for each text input.
Also, you mention that the values must be set with each keystroke, why not instead keep the value of the current input in memory, and bind a function which commits the value both to the blur event of the input, and also use setTimeout to impose, say, a 1 second delay on saving the value, queuing these timeouts in an array, and clearing outstanding ones on each keyup event, that way you're only writing to the local storage when the user pauses typing, not with every keystroke.
As Jamie suggested local storage is a really good approach, cookies could be used as a fallback if Local Storage is not supported.
On the snippet you have provided you have binded the cookie rewrite process in the keyup event, in order to avoid any data loss.
I have implemented a more neat solution , when the user unloads the window I have tried to serialise the form data and store it.
//save data generic function
function saveData() {
var dataObj = JSON.stringify($("input,textarea").serializeObject());
if (!Modernizr.localstorage) {
saveToLocalStorage(dataObj);
} else {
createCookie("jsonobj", dataObj, 1);
}
}
Modernizr is used to detect when local storage is available. Furthermore , I have found that using separate cookies for each field is an overkill, I have used a single JSON string instead.
Full jsFiddele example: http://jsfiddle.net/ARUM9/5/
Further reading:
Local storage :Storing Objects in HTML5 localStorage
Local storage browser support: http://caniuse.com/#search=localstorage
Using JSON serialisation : Serializing to JSON in jQuery
Modernizr documentation: http://modernizr.com/docs/
Use jquery-storage for saving the values https://github.com/julien-maurel/jQuery-Storage-API/blob/master/README.md
Its really simple
$.localstorage.set(inputfield, value)
For setting
$.localstorage.get(inputfield)
For retrieving.
Cookies are often abused for this purpose but cookies get sent to the server on every request. So storing a ton of data in cookies is not a good idea.
Localstorage however was designed for this purpose and is a simpe key value storw in the browser.
Please note that it is a html5 feature and will not work in some older browsers
To circumvent this you can use the cookiestorage provided by jquery storage. But then you also need to include the extra dependencies mentionend in the readme.md
Then use it like this:
var store = $.localstoreage || $.cookiestorage:
store.set(...........

How to read the value of variable in JS in the scope of JSP on the same page?

I have a JSP page in which third party sign-in plugin is used, which is JS. After sign-in is successful, the user-id obtained in JS has to be used in JSP to maintain session by storing that value.
For this, I tried 'manipulating' jQuery but that works only if the JS value is a literal or is pre-known. But here in this case, value is fetched at runtime as per sign in.
Also tried <% String s = "<script>document.writeln(var)</script>"; %>
But again the above problem. works only when value is known before hand.
document.getElementById("ppurl").innerHTML = ppurl; prints the value. But I want to store it.
So, how to achieve the purpose of passing a variable's value in JS to JSP?
Assuming your third party sign-in plugin is client-side JavaScript:
Remember that the JavaScript runs when the page reaches the client. The JSP code has long since completed and so is no longer in the picture.
You have three options that I can immediately see:
Send the data to the server using Ajax or similar.
Refresh the page (sending the login data to the server as part of the refresh).
Update whatever it is on the page that you want to have this value in it via the DOM.
#1 and #2 should be fairly self-explanatory.
For #3: Say you have various forms on the page and you want to make sure that the login token or whatever it is you get from the client-side plugin gets sent with the form using a hidden field in the form with the name tokenField. You could do this:
function putTokenOnForms(token) {
var forms, index, form;
forms = document.getElementsByTagName("form");
for (index = 0; index < forms.length; ++index) {
form = forms[index];
if (form.tokenField) {
form.tokenField.value = token;
}
}
}
You can do much the same with links in a elements (adding to the href property of each link that goes back to your server), etc.
The page outputting the JavaScript to the client cannot read data back from that JavaScript.
You need to initiate a new HTTP request (e.g. using XMLHttpRequest or setting location.href) that passes the data back to the server and then read it in (e.g. from the query string or POST data).
Store it in a cookie using JS. Read it back in JSP.
In your JS, after you get the userID, you can do:
document.cookie = 'myuserid='+userID;
In your JSP, you can read it back like:
Cookie[] cookies = request.getCookies();
String userID;
for(int i = 0; i < cookies.length; i++) {
Cookie c = cookies[i];
if (c.getName().equals("myuserid")) {
userID = c.getValue(); // c.getValue() will return the userID
break;
}
}

Categories