61

How can I embed my rails app into another website via iframe?

It works nicely with RoR 3, but not with RoR 4:

<iframe src="http://myrailsapp.com/" width="100%" height="50" id="rails_iframe">error!</iframe> 

I tried to use verify_authenticity_token and protect_from_forgery options in my controller... seems it's something else (but I'm not sure).

upd. Example: http://jsfiddle.net/zP329/

2
  • Why an iframe? Is there definitely no better option e.g. use an embedded JS widget to access your site data via AJAX? Commented May 17, 2013 at 14:05
  • For me, a coworker was loading my application in his own, personal IFrame'd HTML page that loaded several of his daily sites and tools. jcypret's answer was what I needed Commented Dec 3, 2013 at 14:56

4 Answers 4

104
+50

This has to do with Rails 4 enabling additional security protocols by default: http://weblog.rubyonrails.org/2013/2/25/Rails-4-0-beta1/

The setting that breaks iFrames on remote sites is X-Frame-Options. By default, this is set to SAMEORIGIN, which prevents the content from being loading cross domain:

config.action_dispatch.default_headers = { 'X-Frame-Options' => 'SAMEORIGIN' } 

You can read about the new default headers here: http://edgeguides.rubyonrails.org/security.html#default-headers

In order to allow the iFrame to work cross domain, you can change the default headers to allow X-Frame across domain.

config.action_dispatch.default_headers = { 'X-Frame-Options' => 'ALLOWALL' } 
Sign up to request clarification or add additional context in comments.

5 Comments

After you change the configuration, your browser might still cache the old headers. You can make sure it does not, by opening your iframe in Incognito/Private Window.
"ALLOWALL" is not specified as an option for X-Frame-Options: developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options . Isn't it possible to remove the header?
I should also mention chrome will cache the old value, so you will need to disable the chrome cache in development.
Using a blank string instead of ALLOWALL works in Chromium and Firefox.
53

Rails 4 added a default X-Frame-Options HTTP header value of SAMEORIGIN. This is good for security, but when you do want your action to be called in an iframe, you can do this:


To Allow all Origins:

class MyController < ApplicationController def iframe_action response.headers.delete "X-Frame-Options" render_something end end 


To Allow a Specific Origin:

class MyController < ApplicationController def iframe_action response.headers["X-FRAME-OPTIONS"] = "ALLOW-FROM http://some-origin.com" render_something end end 


Use :after_filter

When you need to use more than one of your action in an iframe, it's a good idea to make a method and call it with :after_filter:

class ApplicationController < ActionController::Base private def allow_iframe response.headers.delete "X-Frame-Options" end end 

Use it in your controllers like this:

class MyController < ApplicationController after_filter :allow_iframe, only: [:basic_embed, :awesome_embed] def basic_embed render_something end def awesome_embed render_something end # Other Actions... end 

Via: Rails 4: let specific actions be embedded as iframes

Comments

2

Update: seems like ALLOW-FROM and ALLOWALL are currently both invalid "X-Frame-Options" header values. The only two valid ones are DENY and SAMEORIGIN and neither allows access from another origin. See MDN documentation: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options.

So looks like response.headers.delete "X-Frame-Options" is the only way now to enable displaying content in an iframe on another site. But I'd love to be proven otherwise if anyone has any knowledge I don't.

Comments

0

I'm working with Rails 6 and Chromium 76. Previous solution with X-Frame-Options is not working. But I've noticed that it works very well when we attach online iframe with JS. So, I just made this simple solution in my view:

<div id='iframe_wrapper' 'data-iframe-content'='<iframe src="https://host.com/"></iframe>'> </div> 

...and add JS code like this:

$(document).ready(function() { var wrapper = $('#iframe_wrapper')[0] wrapper.innerHTML = wrapper.attributes['data-iframe-content'].value }) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.