- Full Guides
- Integration
- Profiles
- Downloads
- More...
Integrating Panda with Ruby on Rails
The following is a guide to integrating Panda into your Ruby on Rails application. However the instructions here can easily be adapted to any Ruby-based web framework or web application.
Before continuing you must have a Panda account. If you haven’t got one yet, you can sign up here. Free accounts are available, great for playing around.
If you are going to deploy your application to Heroku, then start with the Heroku add-on documentation, and then continue with implementation. The process for configuring Panda for Heroku is different to what you’ll read below.
The easiest way to integrate Panda into your application is by using one of the API libraries. The Ruby gem is available from Gemcutter so in most environments you will simply be able to install it using:
sudo gem install panda
For more info on the gem, check out the following documentation:
The example application
This documentation will talk you through the process of integrating Panda with a basic Ruby on Rails application. It will use the libraries linked above.
You can view the code of the complete example, and download it, at the following locations:
Configuration
First you must login to your Panda account to your Panda account at pandastream.com, where you can find your credentials as follows:
- Under Account: Access key, Secret key, API URL
- Under Encoding Clouds: Cloud ID
If you haven’t yet created an encoding cloud you should do so before continuing.
PRO TIP: you may want to create two different clouds, one for development and one for production. Note that each cloud will have a different Cloud ID, but the other credentials will be shared across all clouds.
Once equipped with this information, you can create a Panda config file on config/panda.yml. Just copy the following example and fill it out with your own credentials where appropriate:
development:
api_host: Hostname of your Panda cloud (different for US and EU clouds)
access_key: Your Panda access key
secret_key: Your Panda secret key
cloud_id: Your Panda cloud id
test:
api_host: Hostname of your Panda cloud (different for US and EU clouds)
access_key: Your Panda access key
secret_key: Your Panda secret key
cloud_id: Your Panda cloud id
production:
api_host: Hostname of your Panda cloud (different for US and EU clouds)
access_key: Your Panda access key
secret_key: Your Panda secret key
cloud_id: Your Panda cloud id
In your config/environment.rb file, add the following inside the Rails::Initializer.run do |config| block.
config.gem "panda", :version => ">= 1.0", :source => "http://gemcutter.org"
Now install the gem:
$ sudo rake gems:install
Next create the file initializers/panda.rb and then add the line below to connect to Panda when your app starts.
panda_config = YAML::load_file(File.join(File.dirname(__FILE__),"..", "panda.yml"))[RAILS_ENV]
Panda.configure panda_config
Checking that everything is working
Fire up a console. Your initialiser should run and connect you to Panda.
Now, upload a sample video. You can use any URL; this is the URL of a sample we’ve made available:
>> video = Panda::Video.create(:source_url => "http://panda-test-harness-videos.s3.amazonaws.com/panda.mp4")
Or use a local file:
>> video = Panda::Video.create(:file => File.new("/home/me/panda.mp4"))
Now wait until the video has finished encoding (which could be several minutes). You can check by doing:
>> video.reload
>> video.status
=> "success"
Now you can get the URL of a re-encoded version:
>> video.encodings.first.url
=> http://s3.amazonaws.com/example/e40c1f68fbc1c4db46.mp4
Open this URL in your browser, and you’ll see that Panda has received, re-encoded, and stored your video into your S3 bucket.
Everything’s working great - time to write some application code! If you’d like to play with the console some more, the full set of resources are listed in the API Documentation.
Implementing video uploads in your application

The simplest way to begin uploading videos directly to Panda is using the panda_uploader jQuery plugin. The plugin will automatically detect the user’s browser and provide the user with the best upload method supported. On modern browsers (Safari, Firefox or Chrome), the upload will be done using several advanced features of HTML5. If the browser doesn’t support these, the uploader will automatically fallback to a Flash-based solution using SWFUpload.
Both methods provide the same UI for upload progress, however the upload button will be slightly different. HTML5 uses a native file select form element, and SWFUpload uses an image. To see how to customise those, have a look at the documentation for the panda_uploader library.
In summary, the plugin renders a widget next to a hidden form element. Once an upload is complete, the ID of the new video will be inserted into this hidden field. This ID can then be saved in your application, and will be used to reference the video in Panda later.
Setup models and controllers
Create a Video model to save the ID of the video from Panda, we’ll call it panda_video_id:
./script/generate model Video title:string panda_video_id:string
rake db:migrate
Panda provides its own Panda::Video model, which we’ll wrap with our ActiveRecord model. Edit app/models/video.rb:
class Video < ActiveRecord::Base
validates_presence_of :panda_video_id
def panda_video
@panda_video ||= Panda::Video.find(panda_video_id)
end
end
Now you can access the wrapped object with myvideo.panda_video, or go directly to the encodings with myvideo.panda_video.encodings. This call requires a call to the Panda API, so we cache it with an instance variable to save time.
We’ll use a simple VideosController following the REST pattern. Create app/controllers/videos_controller.rb:
class VideosController < ApplicationController
def show
@video = Video.find(params[:id])
@original_video = @video.panda_video
@h264_encoding = @original_video.encodings.find_by_profile_name("h264")
end
def new
@video = Video.new
end
def create
@video = Video.create!(params[:video])
redirect_to :action => :show, :id => @video.id
end
end
In the show action, we’re first getting a reference to our ActiveRecord object, as normal. Then we’re getting a reference to the wrapped Panda::Video, as @original_video. This object has methods defined in the Panda gem to manipulate the video encodings.
Finally, we’re getting a reference to the actual encoding of the video that’s been performed by Panda, so that we can pass it to the View. When a video is uploaded, one Encoding will be created for each Profile that’s defined. A shiny-new Panda account comes with a single Profile created, called “h264”, but you can create more in your account.
If you’re migrating from an older version of the gem, be aware that your Profiles might not have names. If this step fails, log in to your account and ensure that the string you’re using in find_by_profile_name matches the ‘name’ field.
Finally, add the videos resource to config/routes.rb.
map.resources :videos
map.root :controller => 'videos', :action => 'new'
Create the video upload form
Download the panda_uploader jQuery plugin and copy the latest release to the public folder of your app:
cd /tmp
git clone /docs/uploading_video.git
cp -R panda_uploader/panda_uploader /my_rails_app/public
Create the layout views/layouts/application.html.erb, and include jQuery (version 1.3 or later) and the uploader javascript library:
<html>
<head>
<%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js' %>
<%= javascript_include_tag '/panda_uploader/jquery.panda-uploader-VERSION.min.js' %>
</head>
<body>
<%= yield %>
</body>
</html>
Change VERSION to the version number you have downloaded.
Now create a view which will be the video upload form: /app/views/videos/new.html.erb.
<% form_for @video do |f| %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<!-- file picker will appear here -->
<input type="hidden" name="video[panda_video_id]" id="returned_video_id" />
<div id="upload_progress" class="panda_upload_progress"></div>
<%= f.submit "Upload video" %>
<% end %>
<script>
<% auth_params = Panda.signed_params('post', "/videos.json") %>
jQuery("#returned_video_id").pandaUploader(<%= auth_params.to_json %>, { upload_progress_id: 'upload_progress' });
</script>
The script block obtains a signature from the Panda gem and passes it over to the Flash object so that it can correctly sign the video it is uploading.
For more options, see the panda_uploader documentation.
The Panda Uploader will use HTML5 upload if the browser supports it, and will fall back to Flash upload if necessary:
| Browser | Upload Supported? | Method Used |
|---|---|---|
| IE 6 | Yes | Flash |
| IE 7 | Yes | Flash |
| IE 8 | Yes | Flash |
| Opera | Yes | Flash |
| Safari | Yes | HTML5 |
| Chrome | Yes | HTML5 |
| Firefox 3.5 | Yes | HTML5 |
Set up routes
Now create a basic view to show the video data once it has been uploaded. Edit app/views/videos/show.html.erb:
<h2><%= @video.title %></h2>
<p><%= h @video.panda_video.inspect %></p>
Test video uploading
Start Rails application with ./script/server and visit http://localhost:3000/videos/new where you will see the video upload form. Choose a video (download this splendid video of a sneezing panda if you need a test one) and hit submit. The video will be uploaded directly to Panda, and once complete the form will be submitted to your Rails app, with the upload’s panda_video_id included.
You should now be looking at /videos/1, which will show the detail of the video object. The status should be “processing”. Refresh this page and you will see it change to “success” when the video has finished encoding.
If there is an error when uploading, it’s most likely because the signature is incorrect. Double check you have entered the correct values for the access key, secret key and cloud id. If you can’t solve the issue, don’t hesitate to submit a support ticket and we’ll be able to help you out right away.
Embedding your videos
There are a few options for video playback. Read the Video Players documentation for detailed information. The examples below should be enough to get you started though.
Using HTML5
If you don’t have to support older browsers, the simplest is to use the new HTML5 <video> tag. To support Firefox you’ll also need to add in an OGG source. See the Video Players documentation for details.
Edit your show page in app/views/videos/show.html.erb:
<% if @video.panda.status == "success" %>
<video id="movie" width="<%= @h264_encoding.width %>" height="<%= @h264_encoding.height %>" preload="none"
poster="<%= @h264_encoding.screenshots.first %>" controls>
<source src="<%= @h264_encoding.url %>" type="video/mp4">
</video>
<% end %>
If you refresh the show page you’ll see the encoded video!
Using a Flash player
If you need to support older browsers, you can also offer a Flash player. There are several options including JW Player and Flowplayer. The instructions below are for using JW Player.
Download JW Player, unzip it, and copy player.swf to the public/ in your Rails app. Also copy swfobject.js to public/javascripts/.
Edit your layout in app/views/layouts/application.html.erb and include swfobject.js:
<%= javascript_include_tag 'swfobject' %>
Now, edit app/views/videos/show.html.erb:
<div id='flash_player'>Flash player will appear here</div>
<script type='text/javascript'>
var so = new SWFObject('/player.swf','mpl','<%= @h264_encoding.width %>','<%= @h264_encoding.height %>','9');
so.addParam('allowfullscreen','true');
so.addParam('allowscriptaccess','always');
so.addParam('wmode','opaque');
so.addVariable('file','<%= @h264_encoding.url %>');
so.addVariable('image','<%= @h264_encoding.screenshots.first %>');
so.write('flash_player');
</script>
If you refresh the show page you’ll see the encoded video inside JW Player. This will work on almost any browser with a recent installation of Flash.
Advanced topics
Encoding Profiles
You can change the formats that Panda encodes videos into by logging in to your Panda account. Each Cloud has its own set of Profiles. You can select from preconfigured presets, or create your own by entering the ffmpeg command. To learn more, see the sections on Encoding Profiles and Advanced Profiles.
It’s possible to define several profiles and then decide on a per-video basis which ones to use. When creating your signed params for the panda_uploader, you can specify each profile id that you want to use, separated by a comma:
<% Panda.signed_params('post', "/videos.json", {
:profiles => "756a30a27e1ce34c226a373601fcecf8,db867c70a8105cd4ff74ad3501a3022f"
}) %>
Notification callbacks
Rather than polling Panda to find when a video has finished encoding, Panda allows you to provide a callback url. Whenever an encoding finishes (with success or failure), Panda will make a GET request to this url. See the following example:
<% Panda.signed_params('post', "/videos.json", { :state_update_url => "http://mycallbackurl/$id/finished" }) %>
When Panda calls back, it will substitute $id with the id of the video which has changed state.
Learn more
Now that you have a basic implementation, you might want to check out the Panda Gem Documentation or the full API Documentation for more ideas.
