Topic: Some help with Ruby

I need to put together a text file for a company I'm doing some work for that has to be in a specific format (text delimited).  Each billing code has to be a certain length, say 7 digits.  If the number you're putting in that area isn't 7 digits long, you need to put zeroes in front of it. Like this...

@cost = 4523
I'd like it to output...
0004523

If it's 5 digits long it would still need to work

@cost = 25363
output...
0025363

I need a Ruby method that will evaluate the proper length for that field, and if it's too short, puts the appropriate number of zeroes in front.

Thanks,
Zack

Last edited by zreed20 (2008-10-02 12:04:30)

But they that wait upon the Lord shall renew their strength

Re: Some help with Ruby

I code do this with a case statement, but this seems very ugly...

>> @price = price.to_s.length
>> case
?> when @price = 4
>> '000' + price.to_s
>> when @price = 5
>> '00' + price.to_s
>> when @price = 6
>> '0' + price.to_s
>> else price
>> end
=> "00043.3"

Last edited by zreed20 (2008-10-02 13:29:51)

But they that wait upon the Lord shall renew their strength

Re: Some help with Ruby

>> @cost.to_s.rjust(7, "0")
=> "0025363"

http://www.ruby-doc.org/core/classes/St … ml#M000829

Ryan Heneise  |  Art of Mission  |  Now with extra-strong Donor Tools mojo

Re: Some help with Ruby

ryenski, that's exactly the clean code I knew I should have THANK YOU smile

I'm going to order.order_line_items that I will be iterating through, and will need to output this data into a text file with Windows new line breaks.  Have any advice on that?

Last edited by zreed20 (2008-10-02 14:37:36)

But they that wait upon the Lord shall renew their strength

Re: Some help with Ruby

Well, I've taken ryenski's method and made my report, but it's still not exactly pretty.  I have this all in the Orders Controller.

  def reporter
    @tax_id = '123456789'
    @orders = Order.find(:all, :conditions => ["created_on > ?", Time.now - 30.days])
    f = File.open("/Users/zack/Desktop/general_report_#{Time.now}.txt", 'a+')
    @orders.each do |order|
      order.order_line_items.each do |item|
        @base_price = Item.find(item.item_id).price.to_f
        @subtotal = (@base_price*item.quantity)
        @code = Item.find(item.item_id).code.split(/_/).first.downcase.ljust(10," ")
        @tax = (item.unit_price*0.06)
        @difference = (item.unit_price-@base_price)
        @total = (@subtotal + @tax + @difference + item.shipping_total.to_f)
        f.write(@tax_id)
        f.write(item.agency_code.gsub("-","").rjust(8,"0"))
        f.write(@code)
        f.write(item.quantity.to_s.rjust(7,"0"))
        f.write((number_with_precision(@base_price, precision=2)).to_s.gsub(".","").rjust(8,"0"))
        f.write((number_with_precision(@subtotal, precision=2)).to_s.gsub(".","").rjust(9,"0"))
        f.write(number_with_precision(@tax, precision=2).to_s.gsub(".","").rjust(8,"0"))
        f.write(number_with_precision(@difference, precision=2).to_s.gsub(".","").rjust(8,"0"))
        f.write(item.shipping_total.to_s.gsub(".","").rjust(8,"0"))
        f.write(number_with_precision(@total, precision=2).to_s.gsub(".","").gsub(".","").rjust(10,"0"))
        f.write(order.created_on.strftime("%m%d%Y"))
        f.write(order.order_number)
        f.write("\n")
      end
    end    
    render :nothing => true
  end

It's not working consistently, and it doesn't seem to honor the newline message. Any input is appreciated.

Thanks,
Zack

Last edited by zreed20 (2008-10-06 07:51:15)

But they that wait upon the Lord shall renew their strength

Re: Some help with Ruby

Can you post an example of the output you're trying to generate?

Ryan Heneise  |  Art of Mission  |  Now with extra-strong Donor Tools mojo

Re: Some help with Ruby

Okay,this works, kind of,  but I seem to have to hit the action twice to get the report populated. Here's the output format I want for one line.

12345678901010300ch100     000000100002430+000002430+00000164+00000300+00001095+0000003989+100620087762476

I'm getting it, but on multiple lines, it's like the \n stops working or I have to perform the action 2 or 3 times to get it to populate the report (then I get duplicates...

12345678901000400ch100w    000000112345678901000400ch100w    000000112345678901000400ch100w    000000100002430+000002430+00000164+00000300+00001095+0000003989+100620085703677
123456789010004008350      000000100002725+000002725+00000164+00000000+00000000+0000002889+100620085703677
12345678901014000ch100w    000000200002430+000004860+00000164+00000300+00001095+0000006419+100620085284059
12345678901014000107       000000100002435+000002435+00000146+00000000+00000000+0000002581+100620085284059
12345678901010300ch100     000000100002430+000002430+00000164+00000300+00001095+0000003989+100620087762476

Duplicated 3 times...

12345678901010300ch100     000000200002430+000004860+00000164+00000300+00001095+0000006419+100620082660427
123456789010103008350      000000100002725+000002725+00000164+00000000+00000000+0000002889+100620082660427
1234567890101030013v0527   000000100002870+000002870+00000190+00000300+00000000+0000003360+100620082660427
12345678901010300ch100     000000200002430+000004860+00000164+00000300+00001095+0000006419+100620082660427
123456789010103008350      000000100002725+000002725+00000164+00000000+00000000+0000002889+100620082660427
1234567890101030013v0527   000000100002870+000002870+00000190+00000300+00000000+0000003360+100620082660427
12345678901010300ch100     000000200002430+000004860+00000164+00000300+00001095+0000006419+100620082660427
123456789010103008350      000000100002725+000002725+00000164+00000000+00000000+0000002889+100620082660427
1234567890101030013v0527   000000100002870+000002870+00000190+00000300+00000000+0000003360+100620082660427

You'll notice the second line didn't honor the newline entry.

Thanks,
Zack

Last edited by zreed20 (2008-10-06 14:02:33)

But they that wait upon the Lord shall renew their strength

Re: Some help with Ruby

Okay, this seems to work better, but it seems very strange to call this from a controller...

  def reporter
    @tax_id = '123456789'
    @orders = Order.find(:all, :conditions => ["created_on > ?", Time.now - 30.days])
    File.delete("/Users/zack/Desktop/general_report_#{Time.now.strftime("%m%d%Y")}.txt") if File::exists?( "/Users/zack/Desktop/general_report_#{Time.now.strftime("%m%d%Y")}.txt" )
    sleep 5
    f = File.open("/Users/zack/Desktop/general_report_#{Time.now.strftime("%m%d%Y")}.txt", 'w')
    @orders.each do |order|
      order.order_line_items.each do |item|
        @base_price = Item.find(item.item_id).price.to_f
        @subtotal = (@base_price*item.quantity)
        @code = Item.find(item.item_id).code.split(/_/).first.downcase.ljust(10," ")
        @tax = (item.unit_price*0.06)
        @difference = (item.unit_price-@base_price)
        @total = (@subtotal + @tax + @difference + item.shipping_total.to_f)
        f.write(@tax_id)
        f.write(item.agency_code.gsub("-","").rjust(8,"0"))
        f.write(@code)
        f.write(item.quantity.to_s.rjust(7,"0"))
        f.write((number_with_precision(@base_price, precision=2)).to_s.gsub(".","").rjust(8,"0"))
        f.write("+")
        f.write((number_with_precision(@subtotal, precision=2)).to_s.gsub(".","").rjust(9,"0"))
        f.write("+")
        f.write(number_with_precision(@tax, precision=2).to_s.gsub(".","").rjust(8,"0"))
        f.write("+")
        f.write(number_with_precision(@difference, precision=2).to_s.gsub(".","").rjust(8,"0"))
        f.write("+")
        f.write(item.shipping_total.to_s.gsub(".","").rjust(8,"0"))
        f.write("+")
        f.write(number_with_precision(@total, precision=2).to_s.gsub(".","").gsub(".","").rjust(10,"0"))
        f.write("+")
        f.write(order.created_on.strftime("%m%d%Y"))
        f.write(order.order_number)
        f.write("\n")
      end    
    end
        f.close
        render :nothing => true
  end
But they that wait upon the Lord shall renew their strength

Re: Some help with Ruby

Yes, that is a lot of view code for the controller. I'd probably do it using a custom MIME type and a "txt" view.

1. You'll need a custom mime type for "txt" if you don't have one already. In my app it would reside in config/initializers/mime_types:

Mime::Type.register_alias "text/plain", :txt

2. In the OrdersController, I'd add a line to the respond_to block:

  def index
    @item = Item.find(whatever)
    respond_to do |format|
      format.html # index.html.
      format.txt do
        headers['Content-Disposition'] = %Q{attachment; filename="general_report_#{Time.now.to_s(:db)}.txt"}
      end
    end
  end

3. Then I'd create a view file in views/reports/index.html like this:

<%= @tax_id.ljust(20) %> <%= @item.agency_code.rjust(8,"0") %>+<%= @item.quantity.to_s.rjust(7,"0") %> etc...

Then you can access your report by going to /reports/index.txt, and the browser will process the text file as a downloadable attachment.

Ryan Heneise  |  Art of Mission  |  Now with extra-strong Donor Tools mojo

Re: Some help with Ruby

Thank you very much, that cleans the controller up a ton!  This has been a great learning experience for me.

Zack

But they that wait upon the Lord shall renew their strength

Re: Some help with Ruby

Correction from my post above:

That view file should be named index.txt.erb in order for it to be picked up correctly by the responds_to block.

Ryan Heneise  |  Art of Mission  |  Now with extra-strong Donor Tools mojo