Thursday, December 13, 2007

rSpec and Relationships

I spend a good 3 hours figuring out why my spec tests were failing. Let me explain my scenario to you.


My scenario was pretty much like this: Student belongs to Class.

My test: a student should know what class it belongs to.

My student_spec:
it "should know what class it belongs to"
@student = Student.new
@class = Class.new(:name => "Math")
@class.students << @student
@student.class.name.should == "Math"
end
Failed! Apparently, you cannot insert into the array "<<". You need to do it like this:
@student.class = @class
Well, I'm not that stupid that it'd take me 3 hours to figure that out! My test was longer of course! I just made it simple for example's sake. :P




Monday, December 3, 2007

Rails on Dreamhost

Setting up Rails in Dreamhost is a bit tricky. Dreamhost has a wiki on how to do it but as of today, it doesn't work quite right.

I just installed on and it worked fine so here's how I did it:

1) If you haven't yet, create the user account through their control panel with FCGI enabled.
2) Log on to the user account that you created via shell.
3) type "rails yourappname"
4) type "rm useraccount.dreamhosters.com" since we'll replace it with a symbolic link.
5) type "ln -s yourappname/public/ useraccount.dreamhosters.com"
6) type "cd yourappname"
7) edit public/.htaccess (make sure what you edited isn't the commented line):
RewriteRule ^(.*)$ dispatch.cgi [QSA,L] to RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
8) After require 'fcgi_handler', change the rest of dispatch.fcgi to read:
class RailsFCGIHandler
private
def frao_handler(signal)
dispatcher_log :info, "asked to terminate immediately"
dispatcher_log :info, "frao handler working its magic!"
restart_handler(signal)
end
alias_method :exit_now_handler, :frao_handler
end

RailsFCGIHandler.process!
9) edit your config/environment.rb and uncomment the line:
ENV['RAILS_ENV'] ||= 'production'

10) Your Rails app should be working fine now. You'll need to edit the database.yml and stuff to make sure that you can connect to the database of course.

Goodluck!

Friday, November 16, 2007

Onto Rails and rSpec

Like I mentioned yesterday, I started trying out rSpec. When in Rails, it's a little different. You need to include more stuff. I couldn't get my spec to run properly. Apparently, you have to import a bunch of stuff:

require File.dirname(__FILE__) + '/../../config/boot'
require "#{RAILS_ROOT}/config/environment"
require File.dirname(__FILE__) + '/../../app/models/project_management'

The first two lines I got from the codehappy blog post. The third just imports the model I'm testing out.

I may be doing it completely wrong so I'd appreciate any feed back.

Thursday, November 15, 2007

Command line Subversion, Rails

Like I mentioned on my earlier post, I'm a slow learner when I read manuals. I like watching much more. Check out episode 36 on Railscasts. It gives a nice quick overview on how it's done on the Mac. It's the same on Linux.

Learning Behaviour Driven Development

I've been doing a bunch of Google searches on Behaviour Driven Development (BDD) but all I've found were long articles and wordy introductions. I suppose some people learn that way but I'm way to lazy.

Thank goodness for screencasts. To dive into it, check out the website smartic.us' screencasts on rSpec.

Obviously, I don't know much. All I know is that rSpec is a gem used for testing. He dives straight into making a class and testing it. Or rather, testing it, then making the class. You'll see. :)

Saturday, November 10, 2007

Ubuntu and gVim

I've always been a Windows or DOS user ever since childhood. In the past several years I have tried to migrate to Linux.
Here comes in Ruby on Rails... on gVim... on... Ubuntu. It's nice and fast. you feel like you put your computer on steroids. Enough talk. Let me share with you the simple steps I took to install it.
  1. Install Ruby on Rails so that gVim may be able to access whatever files are in the RoR install.
  2. Go to http://www.cs.cornell.edu/w8/~djm/ubuntu/gutsy/#gvim and follow the installation instructions for gVim.
  3. Go back to my earlier post on Vim and you may follow that and paste the custom files in the gVim ~/.vim/ (which is equivalent to the Window's ~/vimfiles/ folder).
Happy geek out!

Thursday, October 25, 2007

Running Multiple servers

Now this really isn't a hack for rails or a fix. Its a nice little thing built into rails that I just started using. Its running multiple rails programs on a localhost for testing.
Basically, the jist is you can run several RoR servers on the same computer as long as the ports are different.

To achieve this when you run a RoR server with the command :
ruby script/server
you can add a port option by adding -p and specifying the port number:
ruby script/server -p 3001

the default port is 3000, and you can't run multiple servers on a localhost without specifiying a port.

you can also use :Rserver -p 3001 if you are running it on Vim

Wednesday, October 24, 2007

Tackling VIM

Two posts ago I was talking about the RoR talk that Guy gave. Since then, I've learned how to use VIM. There is a bit of a learning curve but you'll see you'll start to work a lot faster about 2 days of continuous use (sleep is ok).

I've found T Pope's article to be very useful. Read that and all the links in the article and the preceding articles.

Stumbling into REST

I stumbled into REST accidentally about 1 month ago. Since then, I've learned to try (at least) to make the URLs more beautiful and this simplifying the sites that I create. Here are some resources I've found to be quite useful:

1) DHH's 2006 keynote
2) Episodes 35 and 67 of Railscasts

If anyone can add to this list, please drop a comment!

Thursday, October 11, 2007

PhRUG Ruby on Rails Talk

I went to a RoR talk last night in Ortigas. It was sponsored by Exist. The speaker was Guy Naor, the CTO of Morph Labs. Because he mentioned a bunch of stuff that I need to remember, here's a list of things people and I should do or at least look into if they are into Ruby on Rails:
  • Continuous Integration
  • Capistrano and SVN
  • The Ruby Way by Hal Fulton
  • Test Driven Development
  • Behaviour Driven Development
  • Vim & Rails
  • Know your regular expressions!
I've looked into these before but I didn't take that much importance to them. Now I know I should look into it some more!

Wednesday, October 3, 2007

You can't upload files via ajax alone!

Spent the morning figuring out something you can't do! I was trying to make an ajax file uploader but kept running into problems. I asked around #rubyonrails in freenode but got no answer so I did some searching... and found a thread of this person that tried to do the exact same thing.

Tuesday, October 2, 2007

helper: Toggler

I made a new helper to help out with toggling a div. To make sure the div is invisible upon load, make sure you add the style="display: none;" in the div.

To call the helper, use it like this:

<%= toggler("click me to open that div", "div-id") %>

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.