I am creating a database for movies (films) and television shows (shows)
that will have has_and_belongs_to_many relationships with the pictures
table.
CREATE TABLE screenshots (
id serial NOT NULL,
filename character varying NOT NULL,
content_type character varying NOT NULL,
primary key (id)
);
CREATE TABLE films (
id serial NOT NULL,
name character varying NOT NULL,
has_subtitles boolean NOT NULL,
is_censored boolean NOT NULL,
episode_no integer NOT NULL,
length character varying NOT NULL,
description text NOT NULL,
release_date date NOT NULL,
file_url character varying NOT NULL,
size double precision NOT NULL,
picture_id integer NOT NULL REFERENCES pictures(id),
primary key (id)
);
CREATE TABLE films_pictures (
film_id integer NOT NULL,
picture_id integer NOT NULL,
“position” integer NOT NULL,
primary key (film_id, picture_id)
);
Here’s the Ruby:
film.rb:
class Film < ActiveRecord::Base
has_and_belongs_to_many :pictures, :join_table => “films_pictures”
attr_writer :uploaded_files
attr_reader :uploaded_files
validates_presence_of :name, :description, :has_subtitles,
:is_censored
end
picture.rb:
class Picture < ActiveRecord::Base
has_many :films
has_many :comics
acts_as_list :picture_id
attr_writer :parent_id
attr_writer :type
validates_presence_of :filename, :content_type
def after_save
p self.inspect
# If a file was uploaded, save it
if @temp_file
# Check the existence of the dir before writing
#item = get_parent
#upload_dir = File.expand_path(UPLOAD_PATH) +
“/#{item.class}/#{item.id}/”
upload_dir = File.expand_path(UPLOAD_PATH) +
“/#{@type}/#{@parent_id}/”
if !File.exists? upload_dir
Dir.mkdir upload_dir
end
# Save the file to /films/123/foo.jpg
destfile = "#{upload_dir}/#{filename}"
p destfile
logger.debug "saving '#{destfile}'"
FileUtils.copy @temp_file.local_path, destfile
#assert File.exists?(destfile), "File upload failed"
end
end
def uploaded_file=(incoming_file)
self.filename = incoming_file.original_filename
self.content_type = incoming_file.content_type
@temp_file = incoming_file
end
def filename=(new_file_name)
write_attribute(“filename”, sanitize_filename(new_file_name))
end
private
def sanitize_filename(file_name)
# get only the filename, not the whole path (from IE)
just_filename = File.basename(file_name)
# replace all non-alphanumeric, underscore or periods with
underscores
just_filename.gsub(/[^\w.-]/,’_’)
end
end
films_controller.rb:
class Admin::FilmsController < ApplicationController
…
def create
@film = Film.new(params[:film])
@film.pictures
# Add each file to the film
params[:pictures].each_with_index {|upload,i|
ss = Picture.new
ss.uploaded_file = upload
ss.position = i
@film.pictures << ss
}
if @film.save
flash[:notice] = 'Film was successfully created.'
redirect_to :action => 'list'
else
render :action => 'new'
end
end
…
end
Film should actually have a has_many relationship with Picture since
there can be only one film per picture, but I am using bridging tables,
and rails only uses the “join table” when there is a habtm relationship.
This seems to work okay, though.
The problem arises when saving the uploaded picture. The pictures are
added to film
The “pictures” table holds the info for all the files that are uploaded.
Each time a file is uploaded, I would like to save it to
“#{RAILS_ROOT}/#{picture_type}/#{parent_id}” where “picture_type” would
be either “film” or “show” and “parent_id” would be the ID of said film
or show object.
Seemingly I have no way of passing the film’s id to the picture. When
Film.save() is called, I need to be able to 1) Save the film 2) Pass the
parent_id and picture_type of the film to each @film.pictures 3) Use
that id and type to create the save path:
“#{RAILS_ROOT}/#{picture_type}/#{parent_id}”. I’m not able to do that
because the film’s id is generated in Film.save, but all the pictures
are also saved in this method.
What I’m wondering is: is there a way to modify each of the
@film.pictures after the film is saved, but before the pictures are
saved (so that I may use the id and picture type).
Thanks to anyone who has read this far