Wednesday, September 26, 2007

helper: s_to_hh_mm_ss

Convert seconds to hh:mm:ss


def s_to_hh_mm_ss(number)
seconds = "%02d" % (number % 6)
minutes = "%02d" % ( (number / 60 ) % 60)
hours = "%02d" % ( (number / 3600) % 24)

return (hours + minutes + seconds).scan(/../).join(':')
end

Tuesday, September 25, 2007

helper: check_box_collection

Following the Lynda.com RoR video tutorials, you're taught how to make code for checkboxes. It's a bit of a hassle because there's a lot of cutting and pasting per checkbox collection you want to have. With the following code, you just paste several times to get things working.

I couldn't find a way to display this properly in blogger, so I posted that code in pastie.
Helper: http://pastie.caboo.se/104016

Code you will put in the model that will "contain the check list". For example, if a user has_and_belongs_to_many :roles, this code will be pasted on the User model.
http://pastie.caboo.se/100607

Then, when you want to generate the checklist, simply paste this in your view:
http://pastie.caboo.se/100609

When updating or saving, make sure you tell the user (or the model that has the checklist) to update! I used mine the following way in the controller:
http://pastie.caboo.se/100608

helper: collection_for_select

I didn't find the form helper that made collection select tags powerful enough, so I made my own. I don't know how to make a nice plugin yet, so it's still a helper.

Code is in pastie.

Put the "helper" section code in your helper file:

For usage, put the code in the "usage" section in your rhtml.

Notes:

* selected_value will only work with integers! It's possible this'll be changed in the future.

[EDIT]
2007-01-03: I changed the pastie code so an error won't be generated even if selected_value is nil

[EDIT]
2007-01-07: If the collection passed is empty, 2 things happen:
  1. The first option with value 0 is "Empty list"
  2. The list is disabled.
If you want to change the message when the list is empty, in the options hash, pass :empty_message

tip: When editing JS, check all that depend on it

The Form.serialize broke when I replaced scriptaculous.js with another version.

tip: tailing logs

You can call this command in Linux to watch a log file as it updates:


tail -f [path/to/filename]


This actually works with all text files.

If you're in Windows, there's no built in DOS command that does it. If you're using Aptana/RadRails, you can right click on the file you want to watch and it'll come out in the console window.

This will remove the hassle of opening and closing the logs whenever we want to see something.

tip: Not using Reserved Words!

Spent 3 hours debugging something - and found out I was using a buggy word / reserved word -- 'display'! Make sure you read the ReservedWords wiki page.

helper: Getting the full URL

There’s nothing built in Rails that gives you the full URL. I made a helper, that gives this to you. It doesn’t display properly here.


def get_full_url(base_url)
return base_url + request.path + get_params_as_url_friendly
end

def get_params_as_url_friendly
count = 0
param_size = request.query_parameters.size
parameters = ""

for param in request.query_parameters
parameter = "#{param[0]}=#{param[1]}"

if count == 0
parameter = "?#{parameter}"
else
parameter = "&#{parameter}"
end

count += 1
parameters += parameter
end

return parameters
end

tip: Going Live with Attachment_fu

This problem popped up in HostingRails.com, and I was using attachment_fu. If you're going live somewhere and you're using attachment_fu, read this thread if you run across errors accessing models that use attachment_fu!

Tutorial: Foreign Keys with Different Names

I had to make private messages that had a sender_id and a recipient_id that both referred to the user table. Here's how the model should look:


class PrivateMessage < ActiveRecord::Base
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
belongs_to :recipient, :class_name => "User", :foreign_key => "recipient_id"
end

Tutorial: Migration Table w/o IDs

When creating HABTM(Has And Belongs To Many) tables, you can create the migration table without an ID column this way:


create_table :events_users, :id => false do |t|
t.column :event_id, :integer
t.column :user_id, :integer
end

Tutorial: attachment_fu: fixing the Windows error on size

It took me a while to find this, but I finally found my answer in a forum thread.

Tutorial: Fixing file_column's permissions

I came across a problem with file_column because it didn't update the permissions of the files and folders where you'd upload.

They'd stay at 600. I'd come across a routing error when trying to download files.

In the file_column.rb I edited the move_from method to look like this:

def move_from(local_dir, just_uploaded)
# create a directory named after the primary key, first
unless File.exists?(@dir)
FileUtils.mkdir(@dir)
#sets the permissions just in case it hasn't been set.
FileUtils.chmod_R 0755, @dir
end

# move the temporary files over
FileUtils.cp Dir.glob(File.join(local_dir, "*")), @dir

@just_uploaded = just_uploaded

# remove all old files in the directory
FileUtils.rm(Dir.glob(File.join(@dir, "*")).reject! {
|e| File.exists?(File.join(local_dir, File.basename(e)))
})

end


Since posting this, we've moved to attachment_fu. It's a lot nicer, but has a steeper learning curve. If you're learning on how to attach files, file_column is fine.

helper: number_to_php

Here's a helper to convert a number to Philippine Pesos. For other currencies, just replace the symbol.


def number_to_php(amt)
return number_to_currency(amt, :unit => "PHP ")
end

Tutorial: Email Authentication When Signing Up

This is to help us remember how to do email authentication (emailing the password to the user, so that they can use that to log in) when signing up.

This assumes you're using the LoginGenerator.

1. In account_controller.rb, add this as a private method:

def generate_password(length = 8)
chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('1'..'9').to_a - ['o', 'O', 'i', 'I']
Array.new(length) { chars[rand(chars.size)] }.join
end


2. Then add/edit this method to the account_controller.rb

def signup
case @request.method
when :post
@password = generate_password

@user = User.new(@params['user'])
@user.password = @password

if @user.save
#@session['user'] = User.authenticate(@user.login, @params['user']['password'])
Notifier::deliver_account_details(@user, @password)
flash['notice'] = "An email has been sent."
redirect_to :action => "login"
end
when :get
@user = User.new
end
end


3. Make the notifier:

ruby script/generate model Notifier


4. Make the method that takes care of the emailing in notifier.rb:

class Notifier < ActionMailer::Base
def account_details(user,password)
# Email header info MUST be added here
@recipients = user.email
@from = "noreply@domain.com"
@subject = "Account Details"

# Email body substitutions go here
@body["username"] = user.login
@body["password"] = password
end
end


5. Create views/notifier/account_details.rhtml like this:

Hello <%= @username %>,

Your password is:
<%= @password %>

When you log in, please change your password for security.

Thank you,
Mailman


6. Finally, add this to the bottom of config/environment.rb:

ActionMailer::Base.smtp_settings = {
:address => "mail.domain.com",
:port => 25, #some servers use 26 - I got stuck here before!
:domain => 'www.domain.com',
:user_name => "info@domain.com",
:password => "pass",
:authentication => :login
}

method: generate_password

Generate a password. Make sure this goes hand-in-hand with encryption. You don't want to store passwords as-is in databases.


def generate_password(length = 6)
chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('1'..'9').to_a - ['o', 'O', 'i', 'I']
Array.new(length) { chars[rand(chars.size)] }.join
end


I got this from "here":http://www.rubyonrailsblog.com/articles/2006/09/29/ruby-on-rails-random-password-generator.

plugin: relative dates

For relative dates: today, yesterday, etc.

Run


ruby script/plugin install http://ar-code.svn.engineyard.com/plugins/relative_time_helpers/


See this for more details:

<%= relative_time(Time.now) %>
# today
<%= relative_time(1.day.ago) %>
# yesterday
<%= relative_time(1.day.from_now) %>
# tomorrow
<%= relative_time_span([Time.now, 5.days.from_now]) %>
# May 17th - 22nd


I got it from http://activereload.net/

Helper: user_authorized?

When using ACLSystem, you can check if someone has permission to do something. However, before you ask, you have to make sure the user is logged in in the first place. Instead of having all that code in the view, I made a helper so that we won't have to check and see if the
session['user'].nil?
each time we want to ask if the user has permission to do so.


def user_authorized?(perm) #works with ACL controller
return session['user'].authorized?(perm) if not session['user'].nil?
return false
end

Documentation

The world of Ruby on Rails doesn't have particularly complete documentation. When looking for a way to convert datetime to a date, I couldn't find a way. I searched in gotapi.com but found nothing.

I went to the #rubyonrails chatroom in EFNet and I was pointed to ruby-doc - another documentation site that I've found to be the best.

Helper: get_url(url)

Answer to making our relative URLs to absolute URLs through the application helper:


def get_url(url)
return "http://localhost:3000" + url
end


If URL were /model/file/1/a.jpg, then you'd get http://localhost:3000/model/file/1/a.jpg in return. When moving to a new webserver, we just need to edit the helper and change the base URL.

Helper: ms_to_hh_mm_ss(number)

Convert a number (milliseconds) the format hh:mm:ss


def ms_to_hh_mm_ss(number)
seconds = "%02d" % (number % 6)
minutes = "%02d" % ( (number / 60000 ) % 60)
hours = "%02d" % ( (number / 3600000) % 24)

return (hours + minutes + seconds).scan(/../).join(':')
end


Place this in the applications_helper.rb to make it available everywhere in the application.

World of Notes

We used to post our code notes - Ruby on Rails notes, CSS notes, etc - in a password protected site.. when we realized we could just as easily share this information with others.

In this blog you'll find posts by different people in the team, talking about the little things we run to everyday, and how to solve them.