Monday, March 30, 2009

Rails Video Application

EDIT: Demo up and running, the URL is http://videoapp.railsonedge.com/

Earlier this semester, I decided I wanted to keep working on my Video Application(see the Flash Video Tutorial). So when my databases teacher let us decide what our semester project would be, I signed up to do a YouTube-like site.

Since the tutorial, I've added a lot of things: User Authentication(authlogic), Video Thumbnails(using ffmpeg), Pagination(will_paginate), Tags/Tag Cloud(acts_as_taggable_on_steroids), and I wrote up some quick code to take care of user replies. I also added a little bit of CSS to the application so it didn't look so plain. It looks a lot better, but I'm still working on some of it. You can checkout the code for it on GitHub(http://github.com/balgarath/video-app/tree/master). The code from the previous tutorial is in the 'Tutorial' branch.

Anyway, I will have a demo of the application up sometime the next couple days. I'll get the URL posted here. Feel free to fork the repo and play around with the app.

Wednesday, March 18, 2009

Yehuda Katz talks about Rails 3.0

Just got through watching Yehuda Katz's talk about Rails 3.0 he gave at MountainWest RubyConf 2009. Lots of good stuff about where Rails is headed, as well as the ORM-abstraction that Yehuda is working on, ActionORM. ActionORM is a layer built to make any ORM look just like it is ActiveRecord, to Rails. Yehuda also talks a little bit about how he is working to change rails so that it will be easier to do things such as changing out ORMs, or even something like replacing ActionController with your own Controller code.


Towards the end he talks about how some people have said that by Merb merging with Rails, there will be less competition, and there will be less competition. Yehuda points out that by making rails modular, competition will be more between different parts of the framework(ActiveRecord vs. Datamapper). I agree with him and think that this will be a huge benefit to the community as a whole. Heres the video:





This video brought to you by ConFreaks. Lots of great videos at the website from many other Ruby-related conferences.

Thursday, January 22, 2009

Flash Video Tutorial with Rails, ffmpeg, FlowPlayer, and attachment_fu

Quick Tutorial today to get a simple Video Model setup and going with Flowplayer today. We want to be able to upload videos and convert them to flash .flv files. For this I'll be using ffmpeg. Other plugins in this tutorial include acts_as_state_machine and Rick Olsen's attachment_fu. Lets get started!



Note: You can find the source code for this app on github at http://github.com/balgarath/video-app/tree/master. EDIT: I've been working on this, so if you want to see the code specific to the tutorial, click on the Tutorial branch on github.

1. Setup



First, lets create an empty app



rails videoapp -d mysql


Do all your basic setup...(edit database.yml, remove public/index, ...). In routes.rb, add this line:


  map.root :controller => "videos"
map.resources :videos

The first line maps '/' to the videos controller, and the next establishes RESTful routes for videos.


Now we need to figure out what flash video player we want to use. For this tutorial, I will be using FlowPlayer, an open-source flash video player. You will need to download flowplayer.zip from http://flowplayer.org/download/index.html. Unzip it to /public. Grab the /example/flowplayer-3.0.2.min.js file and put it in /public/javascripts/flowplayer.js. Put example/style.css in /public/stylesheets.



Next we need to install attachment_fu to handle file downloads.



./script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/


And you will need ffmpeg for converting uploaded file to .swf. This works for me in Ubuntu...


sudo apt-get install ffmpeg


And last, lets install the acts_as_state_machine plugin. We will be using it to keep track of the current state of conversion for the video:


 ./script/plugin install http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk/




2. Database/Model Setup




Now we are ready to set up the model. First, run this command to generate the files for you:



  ./script/generate model Video


This last line will also generate a create_video migration in db/migrate/. Open up that file and put this in it:




class CreateVideos < ActiveRecord::Migration
def self.up
create_table :videos do |t|
t.string :content_type
t.integer :size
t.string :filename
t.string :title
t.string :description
t.string :state
t.timestamps
end
end

def self.down
drop_table :videos
end
end



Content_type, size, and filename are used by the attachment_fu plugin. The state field will be used by the act_as_state_machine plugin to keep track of video converting.



Lets move on to the model; open up /app/model/video.rb and add this into it:




has_attachment :content_type => :video,
:storage => :file_system,
:max_size => 300.megabytes

#turn off attachment_fu's auto file renaming
#when you change the value of the filename field
def rename_file
true
end

This is for the attachment_fu plugin. I came across a feature of attachment_fu: when you change the filename of an attachment, the old file automatically gets moved to whatever the new filename is. Since I am creating a new file and changing the filename attribute of the video the reflect that, I don't need this on...so I just overrode the method in the Model.



Since we will be using the acts_as_state_machine plugin to keep track of the state of conversion for videos, lets go ahead and add in the states we will be using. Add this to video.rb:




#acts as state machine plugin
acts_as_state_machine :initial => :pending
state :pending
state :converting
state :converted, :enter => :set_new_filename
state :error

event :convert do
transitions :from => :pending, :to => :converting
end

event :converted do
transitions :from => :converting, :to => :converted
end

event :failure do
transitions :from => :converting, :to => :error
end

Note: I got some of this part from Jim Neath's tutorial.

Now we can use @video.convert!, @video.converted!, @video.failed! to change the state of a particular Video. The last code we need to add to the model is this:





# This method is called from the controller and takes care of the converting
def convert
self.convert!
success = system(convert_command)
if success && $?.exitstatus == 0
self.converted!
else
self.failure!
end
end

protected

def convert_command

#construct new file extension
flv = "." + id.to_s + ".flv"

#build the command to execute ffmpeg
command = <<-end_command
ffmpeg -i #{ RAILS_ROOT + '/public' + public_filename } -ar 22050 -ab 32 -s 480x360 -vcodec flv -r 25 -qscale 8 -f flv -y #{ RAILS_ROOT + '/public' + public_filename + flv }

end_command

logger.debug "Converting video...command: " + command
command
end

# This updates the stored filename with the new flash video file
def set_new_filename
update_attribute(:filename, "#{filename}.#{id}.flv")
update_attribute(:content_type, "application/x-flash-video")
end




A lot of stuff going on here. Convert will be called from the create action. When called, it sets the state of the video to 'convert' and runs ffmpeg to convert the file to flash(.flv). It will then mark the file as either 'converted' or 'failed'.



Now that that is all done, we can create our database and run the migrations:




rake db:create
rake db:migrate


3. Controller/Views



Now we can generate our controller, model, and view files:



 ./script/generate controller videos index show new


Open up /app/controllers/videos_contoller.rb and put in this code:




class VideosController < ApplicationController


def index
@videos = Video.find :all
end

def new
@video = Video.new
end

def create
@video = Video.new(params[:video])
if @video.save
@video.convert
flash[:notice] = 'Video has been uploaded'
redirect_to :action => 'index'
else
render :action => 'new'
end
end

def show
@video = Video.find(params[:id])
end

def delete
@video = Video.find(params[:id])
@video.destroy
redirect_to :action => 'index'
end
end



In the create method, notice that if the video save is true, @video.convert gets called, which convert the video to .flv.



Views



Create the file /app/views/layouts/application.html.erb and put this in it:




<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>
<title>Video Tutorial</title>
<%= stylesheet_link_tag 'style' %>
<%= javascript_include_tag 'flowplayer' %>
</head>

<body>
<h1>Video Tutorial</h1>

<% flash.each do |key,value| %>

<div id="flash" class="flash_<%= key %>" >
<span class="message"><%= value %></span>
</div>

<% end -%>

<%= yield :layout %>

</body>

</html>



Now for our index view (/app/views/videos/index.html.erb)




<h2>Videos</h2><br />

<%= link_to 'New Video', new_video_url %><br />
<% for video in @videos do %>
<p><%= link_to video.title, video %></p>
<% end %>


/app/views/videos/new.html.erb:




<h2>New Video</h2><br />

<% form_for(@video, :html => { :multipart => true }) do |f| %>
<%= f.error_messages %>
<table>
<tr>
<td><%= f.label :title %>: </td><td><%= f.text_field :title %></td>
</tr>
<tr>
<td><%= f.label :description %>: </td><td><%= f.text_area :description %></td>
</tr>
<tr>
<td><%= f.label :video %>: </td><td><%= f.file_field :uploaded_data %></td>
</tr>
<tr><td><%= f.submit 'Submit' %> - <%= link_to 'Back', videos_path %></td></tr>
</table>

<% end %>



This is the upload form. Notice I used f.file_field :uploaded_data...this is for attachment_fu to work. Next is /app/views/videos/show.html.erb:




<h1><%= @video.title %></h1>
<p><%= @video.description %></p>

<a
href="<%= @video.public_filename %>"
style="display:block;width:400px;height:300px"
id="player">
</a>

<!-- this will install flowplayer inside previous A- tag. -->
<script>
flowplayer("player", "/flowplayer/flowplayer-3.0.3.swf");
</script>



And that should do it. ./script/server and try uploading a movie file and see if it works. Also, you could probably mess around some with the call to ffmpeg and increase video quality. There are some good posts if you search for 'ffmpeg' over at the FlowPlayer Forums, and if you purchase a commercial license for the player, you can remove the advertising and get some new features, as well as support. Thanks for reading!



Update:


For a quick way to put the video conversion on a background process, I was able to use Tom Anderson's Spawn plugin. Note that this wouldn't be a very efficient way to scale it if you expect to have a lot of users uploading at the same time, as it forks another process to handle the conversion. This does work well if there aren't a bunch of videos getting uploaded at the same time. If you do need to scale the uploading, I recommend using Ap4r(Asynchronous Processing for Ruby). Here we go!


First, lets install the Spawn plugin from github:


./script/plugin install git://github.com/tra/spawn.git

And next, change the convert method in Video.rb to this:



# This method is called from the controller and takes care of the converting
def convert
self.convert!

#spawn a new thread to handle conversion
spawn do

success = system(convert_command)
logger.debug 'Converting File: ' + success.to_s
if success && $?.exitstatus == 0
self.converted!
else
self.failure!
end
end #spawn
end

And thats it! Now when you upload a video, you don't have to wait for the server to convert the video file over to flash.

Obama to Save Money by Investing in Open Source?

Came across an interesting article on BBC news today, and thought I would share it. President Obama's staff, in their quest to make budget cuts, have asked Scott McNealy, a co-founder of Sun Microsystems, to prepare a paper on the subject of using Open Source Software as a way to cut costs. Mr. McNealy told BBC that he wanted to make sure the government doesn't get 'locked in' to any specific vendor or company.

I believe it would be a great idea for the government to invest money in Open Source, and would be glad to see some of my tax money being invested in it..as long as the Ruby Community gets its chunk ;).

Friday, August 15, 2008

Juggernaut Push Server


Juggernaut is a Rails plugin that allows you to push information out to the client, without them having to specifically request it. For certain domains, a push server is an excellent solution. Juggernaut uses a small bit of Flash to open up a flashxmlsocket from the browser to the push server, and it subscribes to the service. My roommate Taelor has been playing around with it for a little while, and has put together a chat application that creates rooms off of Digg topics. Its called Shovel Chat. He has also made a few blog posts about Juggernaut and using it to create a chatroom with rails at his blog, and has posted the source code on GitHub(note that you will need to go through his blog posts and edit some of the gem's files...)


So, the way the chat app works is that when you request the show action for a chatroom, some flash gets sent to subscribe to the channel on Juggernaut. Juggernaut will then send you a list of all the people in the room. If you type in a message and hit enter, the message gets posted to your Rails app. Inside the controller, the message gets sent to the Juggernaut server, which then pushes the message out to anyone subscribe to that channel. You could achieve a similar effect using AJAX, but you would have to have each client polling the server for updates to the chatroom, but this would be really difficult to scale.


Anyway, I've gotten his source code installed on my machine and have begun playing around with it, and hope to start contributing to his chat_sandbox on github soon. Feel free to make your own fork of his code on github and start contributing, and stay tuned for more updates!

-Ralph

Tuesday, August 12, 2008

The Ruby Hoedown

Last Thursday, my roommate and I packed and headed 3 hours south to the Ruby Hoedown in Huntsville, AL. It was held at the Shelby Center at UAH on Friday and Saturday. This was my first programming conference, so I thought I might jot down a little bit about how it went.


The first presentation was by the guys at Rails Envy. They talked about innovation in Ruby over the past year. I'm a big fan of these guys' podcasts and tutorials, and they gave a great presentation.


Next up was Robert Dempsey, who talked about Cloud Computing with Rails. He made a great argument against all the folks who say that Rails can't scale. He gave us very detailed explanations of what a Cloud is, and what scalability is. He showed us what it takes to use Amazon Web Services to scale a site up, and then gave us a brief descriptions of different utilities out there for scaling with a cloud: Amazon Web Services, Heroku, Joyent, Accelerator, Morph. One particularly intresting platform was Vertebra, which is being developed by the folks at Engineyard.


Vertebra is a "Next Generation Cloud Computing/Automation Framework". Ezra Zygmuntowicz has some slides posted at his blog. The backbone of the system runs on horizontally scalable erlang XMPP servers. XMPP is an IM/chat protocol this is very efficient. Ezra posted this tidbit on his blog: "Just to answer the question about Vertebra being open source or not. Yes vertebra will be open source, the ruby framework, the protocols and security stuff will all be open source. We may go with a commercial license on the workflow engine as that is a large piece of engineering but we have not decided yet. We want to get this out there and see what people do with it as I think there are limitless possibilities here. But we need to lock down the protocol and document everything and we are still experimenting with different parts of the system. I'd hope to have something to release in 4-6 weeks." Yehuda Katz gave a talk about Vertebra on saturday, and I had a chance to chat with him for a few minutes. He mentioned that some of the folks from Heroku were helping out on the project.


Jim Weirich and Joe O'Brien gave a great talk about mocking. This was an interesting talk because they acted it all out like they were 2 developers working on different problems that involved using mocks. The first one involved using a mock object to log in during testing, and in another one, they showed how you can refactor code so that you will be able to use a mock with it. I chatted with these guys at lunch on Saturday for a while.


Rein Henrich gave a very entertaining talk on Ruby Best Practice Patterns. He started off with a comical presentation on code unfactoring. He showed us different methods of making your code so unreadable that you are the only person able to reasonably maintain it. "Job security through code obscurity." Some of the methods he showed us were: un-DRYing your code; naming methods and variables in pig latin; and taking code that is abstracted into several small functions, and dumping it all into one huge one. After the talk on code unfactoring, he went on into his real presentation on best practice patterns. One of my favorites was the execute around method.


Some other notable talks at the conference included: bryanl(blog smartic.us), who talked about why you should "Test all the fucking time"; the truthy gem; Obie Fernandez's great talk on running a successful company; keynote talks by Chris Wanstrath and David Black; Troy Davis did a presentation on Adhearsion, a ruby framework for making and recieving phone calls; Giles Bowkett used Ruby and his program Archaeopteryx, to create music with code; Being a guitar player, Giles presentation was very interesting to me..unfortunately, Archaeopteryx is only availible for the Mac right now.


I had a great time at the conference. It was cool to be around so many other Ruby enthusiasts, and everybody was really nice. I definitely plan on going next year. Jeremy mentioned that he is planning on holding the Hoedown at Opryland Hotel in Nashville(only an hour away!), and that he hopes to get enough sponsors to host it for free. Even if it isn't free next year, I will gladly pay out another $200 to go again. If you've never been to a conference before, I highly recommend it. It was a very gratifying experience.


Well, thats all for now, I know I promised a post about my Google Summer of Code project, but I don't have it all together yet. If you are interested, it is a c-extension to speed up some of Ruby's CGI functions. You can check out the repo on github here. Farewell until next time!



Edit: Also, you can get videos of all the talks at ConFreaks. I spent a while chatting with both of the guys there, and one of them let me plug in my laptop to their powerstrip for the majority of the conference(I need a new battery...).

Sunday, July 27, 2008

Been a little while...

Hi all, thought I would make a post and update things. I've been busy working on a couple of different gigs: My Place Media, and the Google Summer of Code. Anyway, My Place Media just ran out of money(lots of bad decisions by the guy calling the shots), so I've got a lot more time to concentrate on my GSoC project.


My GSoC project is to working on extending parts of Ruby's CGI class in C (mainly the query string parsing and multipart form parsing). My mentor for the project is Pratik Naik, a Rails Core member. I'll have some more info on how the project is coming along in another post.


Anyway, I've got some ideas for expanding RailsonEdge out a little. The first is that I've purchsed the domain name railsonedge.com, and I have a shared host server. What I would like to do is to use my server to provide hosting for a few open source Rails apps, and let the developers of them either post to the blog, or just put in a feed from their blog. So if there is anyone out there that would like free hosting for your Rails project, to show it to the world, shoot me an email at rledge21 -at- gmail -dot- com, and tell me a little about yourself and your project.


I'm planning on posting some new tutorials very soon (maybe even doing a screencast, but I've not decided whether my voice would scare everybody off or not), and putting up a code snippet repository (similar to snippets.dzone.com)


Anyway, that is what is going on. Expect some posts over the next couple weeks with a couple tutorials, as well as an update to my GSoC project...later all.