Detecting if this is an iframe load or direct - ruby-on-rails

I am looking to only show a form if it is pulled on a page within an iframe. How do I do that? Is there a server side solution?

If you are using JQuery... (installation instructions here: http://jquery.com/ )
$(document).ready(function(){
if( window == window.top) { $('form#myform').hide(); }
});
Which just hides the form with id "myform" if the window is not the topmost window.

I can't think of purely serverside way, but you could use a bit of hybrid javascript/rails.
assuming that you have a dedicated iframe layout template e.g. 'layouts/iframe.erb'
you could put some javascript in the head to check if it is being loaded as an iframe, and if it is not, redirect to an action and maybe display a flash msg "can only load this page inside application"
The javascript/rails for the head
<script type="text/javascript">
function parentExists()
{
return (parent.location == window.location)? true : false;
};
function check_modal(){
if (parentExists()) {
window.location = '<%= url_for( :controller => "home", :action => 'iframe_action', :iframe_fail => 'true')%>'}
}
check_modal()
</script>
notice the param :iframe_fail which you could check for in a controller and do whatever you please if that param is present e.g. display flash msg or redirect
example controller
def iframe_action
if params[:iframe_fail]
flash[:notice] = 'can only load inside app'
else
#do something else
end
end
Not real pretty but might help you get the job done.

My iframe tag was like
%iframe{:height => "98%", :width => "98%",:"id" => "profileIframe"}
I wanted to hide header of my webpage within this iframe hence I used code as:
var $frame = $(window.parent.frames["profileIframe"]).contents();
$frame.find('.header-ui').hide();
If you observe then contents() returns a element as "#document", which is html of iframe, hence calling a javascript without this will try to access your actual webpage rendered in background of iframe.

You can only check it on the client side via JavaScript.
However: DO NOT DO THAT. There are plenty of legitimate uses of putting a site in a (i)frame. Breaking out of such iframe or changing your site in any way in such circumstances them will only make your users pissed unhappy.

Related

Redirect a webbrowser if chrome 18 is not found

I created this script to hide a page only if chrome 18 has not been found, how can I make sure to do the redirect of the url to a external page if chrome 18 has not been found instead of hiding only the page ?
I want to do the redirect to this website http://search.aol.com/aol/webhome
<div id="hiddenContent" style="display: none;">
My hidden content.
</div>
<script>
function GetChromeVersion() {
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
return raw ? parseInt(raw[2], 10) : false;
}
if (GetChromeVersion() == 18)
document.getElementById("hiddenContent").style.display = "";
</script>
It's possible, e.g. by using:
window.location.href='http://search.aol.com/aol/webhome';
Inside your function. BUT I wouldn't recommend you this. You should never trust the client as JavaScript can easily be changed and someone could access your site even despite the JavaScript redirect if they wanted to and made a minimal effort to modify page sources. Javascript is handled on the client-side, while php is completely server-side. In this case I'd use php instead of JavaScript. Try to check it with php and if it's not chrome 18, use: header('Location: http://search.aol.com/aol/webhome');
Edit:
<?php function is_chrome()
{
return(eregi("chrome/18", $_SERVER['HTTP_USER_AGENT'])); }   if(is_chrome()) { header('Location: http://www.search.aol.com/aol/webhome'); } ?>
Place it on top of the file, should work, but haven't tested it yet, if not, just change the string in eregi('chrome/18') to what you need (it's a regular expression)

Rails controller renders JSON in browser

I have a simple controller that I have responding to both html and json. I'm using the json response for a Backbone app. Everything works as expected, except that when I click a link that uses the show method, and then click the back button, the index method just prints a big string of JSON into the browser. If I refresh, it displays HTML as expected. Here's the controller.
class RecipesController < ApplicationController
def index
#user = User.find(params[:user_id])
#recipes = Recipe.all
respond_to do |format|
format.html
format.json { render json: Recipe.where(user_id: params[:user_id]).featured }
end
end
...
end
I tried adding a check for response.xhr?, and only rendering JSON if it was an AJAX request, but that didn't work.
Edit
This is a Rails 3 app not utilizing turbolinks.
Edit 2
Here is the relevant Backbone code.
# app/assets/javascripts/collections/recipe_list_.js.cofee
#App.Collections.RecipeList = Backbone.Collection.extend
url: ->
"/users/#{#userId}/recipes"
model: window.App.Models.Recipe
initialize: (opts) ->
#userId = opts.userId
# app/assets/javascripts/app.js.coffee
$ ->
urlAry = window.location.href.split('/')
userId = urlAry[urlAry.length - 2]
App = window.App
App.recipeList = new App.Collections.RecipeList(userId: userId)
App.recipeListView = new App.Views.RecipeListView
If you're referring to a chrome and turbolinks issue, then an easy fix is to disable caching on ajax requests:
$.ajaxSetup({cache: false})
you could try using /recipes.html
and /recipes.json
and /recipes/1.html and /recipes/1.json
instead of relying on backbone and history to always send the correct headers
I bet it's due to turbolink, or ajax based page rendering (backbone, remote=true, ...)
I always disable turbolink and keep control over which links are remote=true, and for all ajax response I insert this javascript line at the end
history.pushState(null, '', '/the/requested/url' );
If you don't want to manually implement this line for each of your link responses, you can wrap it in an ajax:complete event (more info), and I assume turbolink has an event you can use as well.
Second part of the trick is to bind popstate so when your users click on the "back" button the page will be refreshed from the server (through the url that was pushState-ed earlier) and the ajax/js/json/whatever response won't be displayed anymore.
setTimeout( function () {
$(window).bind('popstate', function () {
window.location = location.href;
});
}, 500);
As you see I wrap the popstate event binding in a setTimeout, because if you don't do that you may have trouble with some browser that would infinitely refresh the page.
Are you using Chrome? if so this is a known issue. When you hit the back button chromes serves the page from cache since what was returned was json that is what it dumps on the screen. This post has some suggested workarounds
https://code.google.com/p/chromium/issues/detail?id=108766

Serve pdf using :remote => true

I have a form_tag that generates a pdf and serves it to the user. The final send_data is like :
send_data pdf.render, type: 'application/pdf', :filename => filename, :compress => true
This works fine with a standar form, but it does not work when i try to use ajax to set :remote => true.
The ultimate thing i want to do is use :disable_with to disable the button while the pdf is generating.
Any ideas on how i could fix this ?
I know is is an old thread but I thought I'd let you know how I got this to work in case anyone else finds there way here as I did.
The problem with using ajax for the request is that the response (the pdf file) is next to impossible to handle and then serve to the user as a file so don't bother. Instead I used rails built in caching to get the pdf served after generation.
Once you have the link working "conventionally" add the :remote => true, :disable_with => 'loading...' to your link to ajaxify it.
Set config.action_controller.perform_caching = true in your config > enviroments > development.rb so you can see this working before pushing to production =p.
Use Action Caching on your download action and set an appropriate expiration if required i.e. caches_action :download, :expires_in => 5.minutes at the top of your controller.
This means that when you click on your link it will send the ajax request, generate the pdf and return the page. Now the page is cached so if you click the link again the request will take milliseconds not seconds. Next all we need to do is a little javascript to download the pdf once its ready.
However you do your javascript (unobtrusively or not) add the following:
$("#download_link").on('ajax:success', function(){
document.location = $(this).attr("href")
});
This will get the browser to follow the link as if the :remote => true wasn't there once the ajax request is successful (i.e. the pdf is generated). Because the response has been cached it'll download immediately.
use a remote link to begin the rendering process
Have your server begin a background job to create the PDF, return to the user a job id
Use javascript to poll the server on a timer, sending the job id and asking if it's complete
Once it is complete, redirect the user to a page where they can download the PDF.
OK, you have to use the various AJAX callbacks.
Assume you have a link on your page to generate the PDF.
<%= link_to 'Generate PDF', '/generate_pdf', :id=>'genpdf', :remote=>true %>
Now you have to bind events to the 'genpdf' element created by the above. i.e.
$('#genpdf').bind('ajax:beforesend', disablepdf)
$('#genpdf').bind('ajax:complete', enablepdf)
Then define the two javascript functions declared above to manipulate the HTML element as needed.
var disablepdf = function() { $("#genpdf").removeAttr("disabled") };
var enablepdf = function() { $("#genpdf").attr("disabled", "disabled") };

Rails 3 - Link to :remote, updating the address URL

I'm currently toying with updating page content via the following:
<%= link_to(content_tag(:span, 'Settings'), edit_admin_store_path, :remote => true)%>
With the javascript as such:
$('nav li a').bind("ajax:success", function(event, data){
console.log(event + data);
$('div#loading').hide();
$('div#container div#content').html(data).hide().fadeIn('100');
});
And was wondering if there is a 'rails way' to also update the address url as well?
Thanks a plenty for any help/advice!
Basically, you are asking for the HTML5 history.pushState method. Great documentation can be found here, at the mozilla developers network.
To be simple, you would push into the history by doing something like this:
var stateObj = { foo: "bar" };
history.pushState( stateObj, "new page title", "forbear.html" )
This will cause the URL to display http://www.yoursite.html/whatever/foobar.html depending on what the URL currently looks like.
Cheers!

Rails 3: How to tell if a user has visited a page before?

I have a Rails app (using Authlogic for authentication) with a simple jquery animation that I only want to run once upon first page load. I know that the key is to check cookies or something to see if the user has visited the page before. Please forgive my n00bness, I know little to nothing about HTTP cookies or sessions.
So, what's the best way to see if a visiting user (even if they haven't logged in) is viewing a page for the first time?
EDIT: Ok, so I realize I wasn't being entirely clear.
I've spent hours looking at similar questions and reading the Rails API Docs for cookies and sessions and I still can't visualize how to implement a visited? function for each page in my site that will only be set to "true" after the user has visited the page the first time. I looked at the supposed "duplicate" question Rails Detect If User's Very First Visit and the respective answers and still can't figure it out.
Here's my "Pages" controller:
def home
#title = "Home"
end
def contact
#title = "Contact Us"
end
dd
And my jquery javascript that does a simple animation:
$(document).ready(function()
{
if (!$.cookie('visited')) {
$('.title .flying-text').css({opacity:0});
$('.title .active-text').animate({
opacity:1,
marginTop: "-150px",
}, 5000);
}
});
I only want it to show if the user HAS NOT visited the page before. I have no idea how to properly set a cookie in Rails, nor where to put it, nor how to make sure that the animation script can access that exact same cookie value. Can someone give me a hand?
~Dan
You can set a cookie like this:
cookies[:welcomed] = {:value => true, :expires => Time.now + 6.months}
and from jquery make a wee function
function readCookie(name) {
var nameEQ = name + "=", ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i += 1) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) === 0) {
return c.substring(nameEQ.length, c.length);
}
}
return null;
}
and call it #in js
if (readCookie('welcomed') == null){}
Ignore the cookie from Javascript.
Using the question referenced as a duplicate, use a permanent cooke and on the first run, set a class on your body from Rails (let's say first-run). Then, have your javascript check and see if body has class first-run. At that point, you can have javascript execute it's first run code.

Resources