Forum: Ruby on Rails Saving an upload

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
61258bd84abdc8003252e93578a3dcd0?d=identicon&s=25 Patrick Clery (Guest)
on 2006-01-09 13:19
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 :)
Cb610750ee94ca103aef4b2dc7b1b768?d=identicon&s=25 Nick Stuart (Guest)
on 2006-01-09 16:57
(Received via mailing list)
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
This topic is locked and can not be replied to.