SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Member
    Join Date
    Feb 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Syntax Questions (relative newbie)

    Hey, I am working on Rails App and I am a bit wobbly on my syntax. I would like to send one of two kinds of send_file statements to a user depending on which kind of downloadable they ordered. I have basically just expanded on the depot code in the Agile Dev book.

    Here is some of the code as it now stands.


    Code:
      
    def download
        begin
          @order = Order.find(params[:id], :conditions => "ordered_at >= DATE_SUB(NOW(), INTERVAL 1 DAY)")
        rescue
          redirect_to_index("Sorry, that's an invalid order.")
        end
        begin
          @file = @order.line_items.find(:first, :conditions => ["deliverable_id = ?", params[:file]])
        rescue
          redirect_to_index("Sorry, you did not order that file.")
          return
        end  
        send_file "#{PDF_ROOT}/#{@file.deliverable.product.title.delete " "}.pdf", :type => 'application/pdf'
      end

    What I would like to change is that last send_file bit to accomodate a statement like the following:

    Code:
    if deliverable.type == 1
        send_file "#{PDF_ROOT}/#{@file.deliverable_id " "}.pdf", :type => 'application/pdf'
    
    if deliverable.type == 2
        send_file "#{MP3_ROOT}/#{@file.deliverable_id " "}.mp3", :type => 'audio/mpeg'
    Also, how might I structure the opposite of this next phrase:

    Code:
    if item.deliverable.download == 0
    I mean how would I state if the deliverable does not equal 0?

    Thanks a ton, in advance. Peace.

  2. #2
    ☆★☆★ silver trophy vgarcia's Avatar
    Join Date
    Jan 2002
    Location
    in transition
    Posts
    21,235
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    Not equal would be != like in most other programming languages

  3. #3
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    To answer your last question, you have two options:

    Code:
    if item.deliverable.download != 0
    Or:

    Code:
    unless item.deliverable.download == 0
    Whichever reads better to you.

    For your main question, I would extract most of the logic to the model and I wouldn't bother storing the uploaded files in separate folders according to type because it makes things simpler and it makes little difference - the file can be stored anywhere and named anything (no file extension needed either) as long as you have a record of the content type in your database - this can be saved when its originally uploaded.

    In the following example, attachments are stored in /var/www/attachments and they are saved using the format attachment_ID

    The model:
    Code:
    class Deliverable < ActiveRecord::Base
      def self.save_path(path)
        @@save_path = path
      end
    
      def attachment_path
        "#{@@save_path}/attachment_#{self.id}"
      end
    end
    Set your attachment path, in application.rb:
    Code:
    Deliverable.save_path = '/var/www/attachments'
    Now your controller code is as simple as:
    Code:
    def download
      begin
        @order = Order.find(params[:id], :conditions => "ordered_at >= DATE_SUB(NOW(), INTERVAL 1 DAY)")
      rescue
        redirect_to_index("Sorry, that's an invalid order.")
      end
      begin
        @file = @order.line_items.find(:first, :conditions => ["deliverable_id = ?", params[:file]])
      rescue
        redirect_to_index("Sorry, you did not order that file.")
        return
      end  
        send_file @file.deliverable.attachment_path, :type => @file.deliverable.content_type
    end
    One gotcha, even though the right content type will be sent for the download, it will simply be named attachment_ID without a file extension. Don't forget you can send a custom name for the file with send_file() so you may want to do that to give the download a more descriptive name (perhaps using some existing metadata you have about the file in the database, or perhaps the original filename if you store that in the db when its originally uploaded).

  4. #4
    SitePoint Member
    Join Date
    Feb 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, House. Like I said, I am completely novice. I would really dig any thoughts you might have on the first part of my question. Thanks again.

  5. #5
    SitePoint Member
    Join Date
    Feb 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks luke, I will give it a go!

  6. #6
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here's an example taken from an app I'm working on at the moment, a knowledgebase module for part of a larger app, where knowledgebase articles can have many attachments:

    Code:
    class KnowledgebaseArticleAttachment < ActiveRecord::Base
    	belongs_to :article,	 :foreign_key => 'knowledgebase_article_id',
    						 :class_name => 'KnowledgebaseArticle'
    
    	validates_presence_of :article, :message => 'is required'
    	validates_presence_of :description 
    						 
    	after_save :store_file
    	after_destroy :delete_file
    						 
    	def self.save_path=(path)
    		@@save_path = path
    	end
    	
    	def uploaded_file=(file)
    		@tmp_file = file
    		self.attachment_name = sanitize_filename(file.original_filename)
    		self.attachment_type = file.content_type
    		self.attachment_size = File.size(file)
    	end
    	
    	def file
    		File.open(self.file_path, 'r')
    	end
    	
    	def file_path
    		"#{@@save_path}/KB#{self.id}"
    	end
    	
    	protected
    		def validate_on_create
    			errors.add_to_base("You must upload a file") unless @tmp_file
    		end
    	
    	private
    		def store_file
    			File.open(self.file_path, "wb") do |f|
    				f.write(@tmp_file.read)
    			end
    		end
    		
    		def delete_file
    			File.delete(self.file_path)
    		end
    		
    		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

  7. #7
    SitePoint Member
    Join Date
    Feb 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Luke, thanks a lot for your help. I am running into problems with the code's structure. I am a novice and trying to get this up and running without too much restructuring of the code/database (since I am so shaky and don't want to dig a deeper hole for myself). That being said is there no way (ruthlessly efficient or not) of keeping the logic basically as is, but having those last two options there at the end of the same controller? You are right about the keeping the files in the same file paths, though, and I will definitely do it that way.

    In any case, I really appreciate it. Thanks.

  8. #8
    SitePoint Guru silver trophy Luke Redpath's Avatar
    Join Date
    Mar 2003
    Location
    London
    Posts
    794
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well the absolutely simplest thing to do given the code you originally posted is:

    Code:
    case @file.deliverable.type
      when 1
        send_file "#{PDF_ROOT}/#{@file.deliverable_id " "}.pdf", :type => 'application/pdf'
      when 2
        send_file "#{MP3_ROOT}/#{@file.deliverable_id " "}.mp3", :type => 'audio/mpeg'
    end
    I'd still advise looking into refactoring things to a better solution though. As long as your code is backed up by unit tests, and with the help of migrations for your db changes, it shouldn't be too difficult.

  9. #9
    SitePoint Member
    Join Date
    Feb 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, a billion, Luke. I will give this a shot. I do think, though, that I will restructure the app in the future, but in the meantime I want to put this out into the world in a functioning state while I learn up on my Ruby knowledge. Thanks.

  10. #10
    SitePoint Member
    Join Date
    Feb 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It worked perfectly. Thanks, Luke.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •