Nested Attributes

The regular disclaimer applies to this post: I’m not a rails expert, so I may not be presenting the “best practices” technique, or a technique that will work for everyone all the time. This works for me, in my use case, and I don’t see any obvious reasons why it wouldn’t work for others.

I have two models I’m working with right now in my project, a collection and a video. A collection is essential a bundle of similar videos that share a title, description, date, etc. This supports the concept multiple formats or slight variations of the same video being used in the system. Its a pretty standard setup in my models:

==Collection.rb==

class Collection < ActiveRecord::Base
has_many :videos
end

==Video.rb==

class Video < ActiveRecord::Base
belongs_to :collection
end

So every entry in the video table has an id in the collection_id field that enables that join to take place. Now its time to get a form that will create a collection and the first video in the collection at the same time… initially I spend time trying to generate a text field (using the text_field form helper) that would be called collection[uploaded_data] {uploaded_data is the field I use on my new video form} but I just couldn’t get that to work. I can’t remember where that naming syntax is used.. maybe its CakePHP, Concerto, or even a different rails technique.. but it wasn’t working.

Googling around for “nested attributes” seem to yield some interesting results, and I stubled onto the accepts_nested_attributes_for concept. I changed my collection model to something like this:

class Collection < ActiveRecord::Base
has_many :videos
accepts_nested_attributes_for :videos
end

Now, I had to add a line (@collection.videos.build) to my collections controller so that it will create a new video object:

def new
@collection = Collection.new
@collection.videos.build

respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @collection }
end
end

Last, but not least, I updated updated my form with the following stuff:

<% form_for (@collection,:html => { :multipart => true }) do |f| -%>
<%= f.error_messages %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %>
<%= f.text_area :description %>
</p>
<p>
<% f.fields_for :videos do |video_fields| %>
<%= video_fields.label :uploaded_data %>
<%= video_fields.file_field :uploaded_data %>
<% end %>
</p>
<p>
<%= f.submit ‘Save’ %>
</p>
<% end -%>

Now the save stuff is all handled by the exact same save I used for the regular collection entry, no need to updated that. Whew!

Here are some additional resources I found helpful:

To database or not to database

For the past week or so I’ve been thinking about the storage of video files, and how to implement a storage system that is fast, effecient, secure, and reliable. My big question here is to use a database or not to use a database. I’m likely using MySQL for everything else, but video files are a bit larger than you VARCHAR(255) or even larger than a photo gallery image I’d store in a database. I’m concerned that throwing video files, ranging from 100MB to 5GB in a database might start to slow things down… which I really don’t want to happen. On the other hand, I can’t afford to have video files laying around in violation of a database foreign constraint, which might happen if a user deletes a video and the file delete fails (maybe its in use).

I’ve done some work storing large datasets in MySQL, but no work storing >25MB in a single field. Of course there would have to be a seperate media table, to prevent a stray ‘SELECT * FROM videos’ fr0m crashing the whole thing. but that still doesn’t convince me it will be as fast as it needs to be.

Another nice plus on the filesystem side is the mod_flv and mod_h264 streaming plugins for Apache. I know you can write a version of the flv streaming module in PHP, but I don’t see it having the speed of an Apache plugin.

I think ideally I’d like to store videos in the database or using something besides the regular flat file approach. Using Ruby on Rails might make this a moot point from a programming perspective, attachment_fu easily handles both file and database datastores.

If you have any experience storing large files in a database, I’d love to hear about it.