Saving an upload


#1

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 :slight_smile:


#2

Is there any reason why a picture would be related to more then one
file or show? It seems the has_many :films is out of place in the
pciture class. A belongs_to :film would make more sense I think. (to
me anyways)

Doing it this way removes the join table you have, and simplifies the
model. AND in the picture you can also do self.film.id to get the film
id.

Also might be handy if you post the structure of the pictures table.

From the look of it, a picture can be related to other pictures?
(attr_writer :parent_id) But its incomplete because you dont have any
other relationship defince for this. If this is the case you cans
simply put:
belongs_to :parent, :class_name => “Picture”, :foreign_key =>
“parent_id”
which gets you all the methods you need to add child pictures (there
are other macros too, such as acts_as_tree that give you similar
functions)

Hope this helps!
-Nick