I would like to make my web page that I coded with Ruby on Rails as backend embeddable so that users are able to easily share it by copy and pasting some embed code. (much like YouTube embed code, but for a webpage)
Could someone point me to a tutorial or general direction how to go about doing so?
I'm planning to embed my web page in Joomla CMS.
Many thanks.
Pier.
Let's suppose you want to create a Widget for a mobile app store. The widget would allow to embed information of a certain app in any web page.
If we use the script tag, the embeddable code could look like this:
<script src="http://my_appstore.com/apps/1234.js" type="text/javascript"></script>
Where 1234 would be the id of the specific app we would like to embed.
If we use the iframe tag the code to put in other web pages could look like:
<iframe src="http://my_appstore.com/apps/1234" width="500" height="200" frameborder="0"></iframe>
First thing we have to decide is what kind of tag to use. Using and iframe tag is more straight forward but we are limited to use an iframe. Using an iframe is not a bad option but if you distribute this to third party web pages you won't be able to change that afterwards. Instead, it is preferable to use a script tag that will insert an iframe. This tag will also allow you to switch to embedding your content directly into pages if you choose to do so afterwards.
Inserting an iframe means that the proportions of your content have to be fixed and can't change to adapt to different window sizes in the parent window. Embedding your content directly doesn't have this problem but you have to be very careful with CSS and add style to all your elements because otherwise they will inherit the host page styles. Also embedding your content directly and then making AJAX calls will likely produce cross-browser request problems unless you use JSONP.
Let's first create a simple web page with Sinatra that we will use to embed our Rails Widget:
mkdir host_page
cd host_page
With your text editor create host.rb file inside host_page folder:
# host.rb
require 'sinatra'
get '/' do
erb :index
end
Create index.erb and launch host_page:
mkdir views
cat '<script src="http://localhost:3000/apps/1234.js" type="text/javascript"></script>' > views/index.erb
ruby host.rb
Now if we visit http://localhost:4567/ we see nothing but there will be a widget there soon.
Let's now create the rails app that will be embedded. Start with a new folder for your project and do:
rails new widget
cd widget/
rails g controller apps
rm app/assets/javascripts/apps.js.coffee
Add the needed routes:
# config/routes.rb
MyApp::Application.routes.draw do
resources :apps
end
Edit your apps controller:
# app/controllers/apps_controller.rb
class AppsController < ApplicationController
def show
#mobile_app = {
:title => "Piano Tutorial",
:descr => "Learn to play piano with this interactive app",
:rating => "*****"
}
end
end
In that controller we are always returning the same app. In a real situation we would have a model and the controller that would retrieve the appropriate app data from the model id found in params.
Create your javascript view and start the server:
echo 'document.write("<h3><%=#mobile_app[:title]%></h3><p><%=#mobile_app[:descr]%></p><p><em><%=#mobile_app[:rating]%></em><p>");' > app/views/apps/show.js.erb
rails server
And that's it. Go to http://localhost:4567/ and see your widget.
In case you want to use an iframe, replace the contents of your show.js.erb file with this:
document.write("<%=escape_javascript(content_tag(:iframe, '', :src => app_url(params['id'])).html_safe)%>");
Here we are using a content_tag but it could also be done in a way similar the previous one by just using the <iframe> tag as previously.
Obviously if we use an iframe, we are doing two calls, one to render the iframe and the other one to load the contents of that iframe. For this second call we are still missing an html view. Just create the view like that:
# app/views/apps/show.html.erb
<h3><%=#mobile_app[:title]%></h3>
<p><%=#mobile_app[:descr]%></p>
<p><em><%=#mobile_app[:rating]%></em><p>
Now you can point again to http://localhost:4567/ and see your widget inside an iframe.
A bit late, but I stumbled over this Question while searching for a solution by myself. I found a Gem that does exactly what's described. It will make your rails app embeddable like YouTube Videos or Content from other Webpages like Google Maps, Instagram, Twitter… It's called EmbedMe
To use you simply need to change your Routes to define, which Paths need to be embeddable
get 'private', to: 'application#private'
embeddable do
get 'embeddable', to: 'application#embeddable'
end
Gem on Github or Documentation
In case anyone is coming across this now, almost 9 years later...
If you use the JavaScript method, you'll have to allow Cross-Origin requests, like #abessive mentioned in their comment above. I was able to do this by adding this to the top of my controller class:
protect_from_forgery except: :method
where :method is the method that will be called for the embed request.
Here's my controller:
class PagesController < ApplicationController
protect_from_forgery except: :home
def home
render 'index.js'
end
end
And the relevant route in routes.rb:
get "index.js", to: "pages#home"
And I have views/pages/index.js.erb with some JS code that renders the widget.
(I'm using Rails 6.1.4)
Related
Two questions.
Number 1:
This is how I am creating the frames in .erb files.
<frameset rows="170,*" frameborder="0" border="0" framespacing="0">
<frame name="topNav" src="top_nav.html">
</frame>
</frameset>
I have couple more frames inside above frameset. If I run this code, I get "No route matches [GET] "/top_nav.html". Question is: Is it really necessary to create/config routes of all the src locations specified in the frame tag?
Number 2:
In my application, I would need to change links in my app very frequently. If I need to consider the routing, I would need to create routes more frequently. Right? How can I avoid consider the routes? Basically, If I add any link in my app, it should work irrespective of fact that whether I have added the routes or not.
You can put a static html page in your /publics folder, which will bypass rails routing and be served directly if e.g. someone visits website.com/top_nav.html, it'll serve up public/top_nav.html. The reason you're getting this error without visiting it is because the frame tries to load the src when you load the frame.
If you just want to serve a blank page as a catch-all for missing pages, you could create a controller that catches anything without another matching route, like so:
# config/rotues.rb
# make sure this is at the BOTTOM of your routes.rb
match "*path", to: "application#default", via: :all
And then in your application controller:
def default
render nothing: true
end
This probably isn't the best way to handle it, though. You'd be best having the links you want created and served dynamically, but that'd depend on what your application is doing.
I have a rails site running done using the bootstrap. There's a mobile and tablet site for the same. Mobile and tablet site have completely same feature apart from having a slightly different index page.
I have used this railscast to load the app on the mobile device.
Is it possible to have another url like used in the article for tablets.
For eg for mobile, localhost:3000/pages/home?mobile=0
This is what can be used. Can we use something like this for tablets?
Like we write media queries for CSS, Is it possible that I write different HTML in mobile.html file and load that chunk of code for tabs, As I need a small change to the index page only.
Please suggest.
It has to be rails centric
You'll want to use request.user_agent:
if request.user_agent =~ /android|blackberry|iphone|ipad|ipod|iemobile|mobile|webos/i
## mobile
else
## not mobile
end
So you could do something like this:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def mobile?
request.user_agent =~ /android|blackberry|iphone|ipad|ipod|iemobile|mobile|webos/i
end
helper_method :mobile?
end
#app/views/pages/home.html.erb
<%= render "small_change" if mobile? %>
--
Some refs:
Rails 3 detect request coming from mobile clients
Rails way to detect mobile device?
Update
The above allows you to call the mobile? method in any view you need.
Because it's in the application controller, it has access to the request object (otherwise you'd have to pass it to the action each time).
So when you asked:
So where should I put that code in mobile's index.html. As I don't want to add other files
... there is no "mobile" index.html.erb. You can call the mobile? method in any view you need:
#app/views/pages/home.html.erb
<% if mobile? %>
.... do something here.
<% end %>
Less is more. Keep it simple. I propose a simple jquery/html/css solution. Have one and only one file. Modify the different areas of the html file via unique class names. In this case I have desktop coding or mobile coding. In your case you can split it up as you see fit, obviously by modifying the if statement shown below.
In html:
<main id="top_main" class="website_desktop">desktop content goes here.</main>
or
<main id="top_mobile" class="website_mobile">mobile content goes here.</main>
In script:
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
// display stuff for mobile
jQuery("#top_main").css("display", "none");
jQuery("#top_mobile").css("display", "block");
}else {
// hide all stuff for mobile, display desktop
jQuery("#top_mobile").css("display", "none");
jQuery("#top_main").css("display", "block");
}
ID's are used for script, classes are used for different CSS controls (in my example, mobile vs desktop)
Ruby 2.0, Rails 4.0, PSQL 9.3
In the ActiveAdmin documentation there is the example:
ActiveAdmin.register_page "My Page" do
content do
para "Hello World"
end
end
Where do I put this code? The documentation says:
In the above example, a new page will be created at /admin/my_page
with the title “My Page” and the content of “Hello World”.
This implies that such a file would be created automatically somehow? Nevertheless, I created a file named import.rb under app/admin and the Import item in the menu does appear. However, I am not able to use HTML, as this file is .rb and not .erb. I suppose, in order to be able to use html, I need to create a partial and den render it within the content method. But when I look under app/views there is not admin folder (only layouts). Does this mean I need to create the folder admin under app/views? If yes, where should I put my partial - directly under app/views/admin or under a new folder app/views/admin/import?
I am sorry for the menu questions, but the documentation of ActiveAdmin is pretty modest. I would really appreciate if someone could provide a more details explanation of the steps needed for creating and adding content to a new page in ActiveAdmin.
What the documentation meant was that if you create a new custom page app/admin/my_page.rb, this page will be available in the URL /admin/my_page (if you are using the default ActiveAdmin configuration).
Regarding rendering of an ERB or HAML partials for your my_page.rb, you can do it this way:
ActiveAdmin.register_page "My Page" do
content do
render :partial => 'about'
end
end
This will look under the directory app/views/admin/my_page/. If the directories do not exist, create them. Also, you can still specify other directories by referencing the full template path (e.g. shared/sections/about) like you would for a non-ActiveAdmin controller.
I have a rails app with content other websites need to access via iframe.
The content should have a different layout when shown on the websites (no menu bar etc.)
I made a new layout file called iframe.html.erb
How can I check, whether the page is called form an external iframe so the right layout file is used?
As far as I know when you doing
<iframe src="www.google.pl"></iframe>
you have no control over layout or styles of page display in iframe unless you own the page and can make it look whatever you like.
EDITED
If you displaying your own site go like this:
<iframe src="/some_site_that_i_can_change_code_in?from=iframe"></iframe>
and then in controller of some_site_that_i_can_change_code_in:
if params[:from] == "iframe"
render :layout => "for_iframe"
else
render :layout => "normal"
end
A good way to control the specific layout and content when serving an iframe is to register an "iframe" mimetype.
## config/initializers/mime_types.rb
Mime::Type.register 'text/html', "iframe"
Create a view that matches the controller action being served ie: show.iframe.haml. Then, when a request comes in with format: iframe it'll render the iframe version.
That way you can control exactly what's in the iframe on other sites. No need to get crazy in the controller.
I think the only way to do this is with Javascript and then redirect, but it's kind of messy and not really a good idea. See this thread for more info: Detecting if this is an iframe load or direct
I have several static files(pages), which are basically copies of my website pages source code, with the content changed.
These files support my website, (keeping the same format) in various ways.
For example the menu part is:-
<body>
<div id="menu">
<ul class="level1" id="root">
etc
etc. until
</ul>
</div>
Unfortunately every month or so my menu bar changes and I have to update each static file manually.
As each of my static files have the same menu.
Is it possible to have one menu file which can be updated and have the static files load them automatically.
I plan to have several more static files. So this would be a great help if someone can suggest how to accomplish this.
Oh yes. Use some javascript magic to load the menu bar upon page load and keep it in menu.html.
One solution may be to use a spider (wget --recursive) to download generated pages directly from your application. One command, and you have the full copy of your site. (just add some useful options, like --convert-links, for example).
The other option may be to write an after_filter in your controller, and write the generated content to a file (not always, but for example when you add a parameter ?refresh_copy=1). Maybe just turning on page caching would be suitable? But the problem will be that you will not be able to trigger the controller action so easily.
If you don't want the whole site copied, just add some specific routes or controllers (/mirrorable/...) and run the spider on them, or just access them manually (to trigger saving the content in the files).
I ended up creating one controller without a model.
rails g controller staticpages
I then created a layout file which imported the individual changes to the layout, via a "yield" tied to a "content_for" in the view files(static files(pages) in the "view of staticpages" (for example abbreviations, aboutthissite etc etc).
The rest of the static file loaded with the usual "yield" in the layout. Works a treat. No more updating the menu bar all done automatically.
To get to the correct static file I created a route using:-
match 'static/:static_page_name'=> 'staticpages#show' (or in rails 2.x:-
map.connect 'static/:static_page_name', :controller=> "staticpages", :action=> "show"
"static_page_name" variable accepted anything after "/static/" in the url and passed it to the controller "staticpages" in which I set up a show action containing:-
def show
#static_page_name = params[:static_page_name]
allowed_pages = %w(abbreviations aboutthissite etc, etc,)
if allowed_pages.include?(#static_page_name)
render #static_page_name
else
redirect_to '/' #redirects to homepage if link does not exists
end
end
I then only had to change the links in the website. (e.g.<%= link_to " About This Site ", '/static/aboutthissite' %>)
and viola! its all working.