For whatever reason you need or choose to store blobs in databases. Yet, you do not wish to mix blob columns in the same table as your regular attributes. BinaryColumnTable helps you store ALL blobs in a separate table, managed transparently by an ActiveRecord model. Optionally, it helps you record the content-type of the blob.
This plugin does nothing else.
In your existing model, e.g. Member, declare your binary columns (note: these columns does not exist in your “members” table)
classMember<ActiveRecord::Basehas_binary_columns:photo, :resume, :secret_zipend
For that to work, generate a model called BinaryColumn to contain these blobs.
rails generate model BinaryColumn original_table_type:string original_table_id:integer name:string content_type:string original_filename:string content:binary
You may wish to edit the generated migration file to add a custom index to the bottom of the “self.up” method,
classCreateBinaryColumns<ActiveRecord::Migrationdefself.upcreate_table:binary_columnsdo|t|t.string:original_table_typet.integer:original_table_idt.string:namet.string:content_typet.string:original_filenamet.binary:contentt.timestampsendadd_index:binary_columns, [:original_table_id, :original_table_type, :name], :name=>:by_owner_field_name# add this lineenddefself.downdrop_table:binary_columnsendend
Then apply the schema change,
rakedb:migrate
Finally, modify the generated app/models/binary_column.rb to have a polymorphic “belongs_to”
classBinaryColumn<ActiveRecord::Basebelongs_to:original_table, :polymorphic=>truedeffile_extensionself.original_filename.to_s.split('.').lastendend
The usage is simple and straight-forward as-if the columns are in the original table.
m = Member.newm.name = "Michael"m.photo = IO.read("avatar.png") #=> binary stringm.resume = File.open("resume.doc") #=> IO object (e.g. when uploading via http form)m.save!#=> creates a record in "members" table, saving "Michael" into the "name" column#=> creates a record in "binary_columns" table, saving "avatar.png" binary into "content" column#=> creates a record in "binary_columns" table, saving "resume.doc" binary into "content" columnm = Member.lastm.name#=> "Michael"m.photo_attributes#=> light-weight loading of BinaryColumn object (excludes BLOB)m.photo_attributes.file_extension#=> "png"m.photo#=> binary content of the "avatar.png" filem.resume#=> binary content of the "resume.doc"
Note: If you MUST have your binary column table called something other than “binary_columns”, just edit ActiveRecord::Extensions::BinaryColumnTable::CLASS_NAME
Note: Population of the “content_type” attribute requires “file” command on OS, i.e. most Unix otherwise, remove “content_type” column from table definition to skip content_type extraction
Note: Accessing the content_type attribute is not sugar coated, add a “_binary_column.content_type” suffix. i.e. from our earlier example
m = Member.lastm.photo#=> binary content of the "avatar.png" filem.photo_binary_column.content_type#=> "image/png; charset=binary"
You may wish to generate index for that table as well
./script/generate migration AddIndexesToBinaryColumns
Edit the generated db/migrate/*_add_indexes_to_binary_columns.rb to look like this
classAddIndexesToBinaryColumns<ActiveRecord::Migrationdefself.upadd_index:binary_columns, [:original_table_id, :original_table_type, :name], :name=>'by_original_table_name'enddefself.downremove_index:binary_columns, :name=>'by_original_table_name'endend
Then run migration to commit the schema change
rakedb:migrate
Copyright © 2009 Chew Choon Keat, released under the MIT license