Thursday, December 20, 2007

AES encryption and decryption in Ruby

AES encryption and decryption in Ruby is very simple, although I had a hard time finding documentation on how to do it. Ruby has a wrapper over OpenSSL, but I had trouble finding documentation on how to use OpenSSL as well. I found a pretty good piece of code at http://snippets.dzone.com/posts/show/576.

Using this and other information that I found, I created a module for encrypting and decrypting blocks of data. It isn't just limited to AES encryption and decryption, since OpenSSL supports many other types of encryption, but I only use it for AES 256. To get a list of the types of encryption that OpenSSL uses (and what the string would be that you pass in to my functions as cipher_type), open a command prompt, type openssl, then help, and the cipher types are listed under cipher-commands. The two types for AES 256 encryption are "AES-256-CBC" and "AES-256-ECB". Here is my module:


require 'openssl'

module AESCrypt
# Decrypts a block of data (encrypted_data) given an encryption key
# and an initialization vector (iv). Keys, iv's, and the data
# returned are all binary strings. Cipher_type should be
# "AES-256-CBC", "AES-256-ECB", or any of the cipher types
# supported by OpenSSL. Pass nil for the iv if the encryption type
# doesn't use iv's (like ECB).
#:return: => String
#:arg: encrypted_data => String
#:arg: key => String
#:arg: iv => String
#:arg: cipher_type => String
def AESCrypt.decrypt(encrypted_data, key, iv, cipher_type)
aes = OpenSSL::Cipher::Cipher.new(cipher_type)
aes.decrypt
aes.key = key
aes.iv = iv if iv != nil
aes.update(encrypted_data) + aes.final
end

# Encrypts a block of data given an encryption key and an
# initialization vector (iv). Keys, iv's, and the data returned
# are all binary strings. Cipher_type should be "AES-256-CBC",
# "AES-256-ECB", or any of the cipher types supported by OpenSSL.
# Pass nil for the iv if the encryption type doesn't use iv's (like
# ECB).
#:return: => String
#:arg: data => String
#:arg: key => String
#:arg: iv => String
#:arg: cipher_type => String
def AESCrypt.encrypt(data, key, iv, cipher_type)
aes = OpenSSL::Cipher::Cipher.new(cipher_type)
aes.encrypt
aes.key = key
aes.iv = iv if iv != nil
aes.update(data) + aes.final
end
end

Thursday, December 6, 2007

Assigning values to has_many through relationships

I found out the hard way today that you can't directly assign values to a has_many :through relationship like you can with a has_and_belongs_to_many relationship. First let me explain the two approaches for many to many relationships if you're not sure what they are.

Say you have a "group", and groups can have any number of accounts. Accounts can also belong to any number of groups. You can accomplish this two ways. First, create a join table called accounts_groups, with no id, and two primary keys, account_id and group_id. Then simply put this one line in the group class
has_and_belongs_to_many :accounts

and this in the account class
has_and_belongs_to_many :groups

The downside of this approach is that you can't have additional information about the association (like number_of_logins, etc.). If you don't need additional information about the association, I think has_and_belongs_to_many (habtm) is the better approach (less code, less complicated), even though this seems to have fallen out of favor in the Rails community.

If you do need information in the association, or you just want to use the Rails community's preferred approach, first create a join table named memberships, with a primary key id, account_id, and group_id. Then add a class named Membership:
class Membership < ActiveRecord::Base
belongs_to :account
belongs_to :node
end

Add this to your group class:
has_many :memberships
has_many :accounts, :through => :memberships

And this is your account class:
has_many :memberships
has_many :groups, :through => :memberships

One downside of has_many :through is that you can't assign directly to the relationship. For the above example, say you had an array of accounts that you want to assign to a group. You can't code
@group.accounts = array

But you can with habtm You can also assign an array of id's to a has_and_belongs_to_many relationship by using relationship_ids = array. Note that it's the singular form of the relationship in the name of the function. One more reason to use habtm.

BUT I found a really good function to allow you to assign values to has_many through relationships at the Grinding Rails blog (http://tuples.us/2007/05/09/metaprogramming-has_many-through-accessors/). It's really useful when using has_many through relationships.

Sunday, December 2, 2007

Formatting Ruby and HTML code for blog posting

I just found a better way to format code for blogs. Read my blog post Better way to format code for blog posts to see how. I'll leave the old way here, in case you want to still use this way.

Posting Ruby and HTML that looks good here on Blogspot can be a pain. But I found a ruby gem called Syntax that will format Ruby code to look right on web pages. It can also do the same thing for HTML/XML. I found out about this at http://blog.wolfman.com/articles/2006/05/26/howto-format-ruby-code-for-blogs. To install it, just type:
gem install syntax

at the command prompt. Then add this to your CSS declaration.
pre {
background-color: #f1f1f3;
color: #112;
padding: 5px;
font-family:"bitstream vera sans mono",monaco,"lucida console","courier new",courier,serif;
font-size: 0.9em;
overflow: auto;
margin: 4px 0px;
width: 95%;
}



/* Syntax highlighting */
pre .normal {}
pre .comment { color: #005; font-style: italic; }
pre .keyword { color: #A00; font-weight: bold; }
pre .method { color: #077; }
pre .class { color: #074; }
pre .module { color: #050; }
pre .punct { color: #447; font-weight: bold; }
pre .symbol { color: #099; }
pre .string { color: #944; background: #FFE; }
pre .char { color: #F07; }
pre .ident { color: #004; }
pre .constant { color: #07F; }
pre .regex { color: #B66; background: #FEF; }
pre .number { color: #F99; }
pre .attribute { color: #5bb; }
pre .global { color: #7FB; }
pre .expr { color: #227; }
pre .escape { color: #277; }

For blogspot, just click Template, and Edit HTML.

I wrote up a Ruby script using this gem for Windows that will read Ruby code from the clipboard in Windows, format it for HTML, and paste the HTML back to the clipboard. For some later Ruby versions you'll need to run "gem install win32-clipboard". Here is the code:
require 'syntax/convertors/html'
require 'Win32API'
require 'win32/clipboard'
include Win32

in_data = Clipboard.data
convertor = Syntax::Convertors::HTML.for_syntax "ruby"
code_html = convertor.convert(in_data)
Clipboard.set_data(code_html)
And I also wrote one for formatting HTML or XML code. Notice that the only thing different is the for_syntax line.
require 'syntax/convertors/html'
require 'Win32API'
require 'win32/clipboard'
include Win32

in_data = Clipboard.data
convertor = Syntax::Convertors::HTML.for_syntax "xml"
code_html = convertor.convert(in_data)
Clipboard.set_data(code_html)


For other OSes, here is code that will read a file "input.rb" and convert it to HTML in the file output.html:
require 'syntax/convertors/html'

in_data = File.read('input.rb')
convertor = Syntax::Convertors::HTML.for_syntax "ruby"
code_html = convertor.convert(in_data)
File.open('output.html', 'w') {|f| f << code_html }

And here is the code to convert HTML or XML from the file input.html into output.html:
require 'syntax/convertors/html'

in_data = File.read('input.html')
convertor = Syntax::Convertors::HTML.for_syntax "xml"
code_html = convertor.convert(in_data)
File.open('output.html', 'w') {|f| f << code_html }


The only complaint is that sometimes line breaks are displayed on the web page in your code in Internet Explorer when there shouldn't be. The scroll bars show up, but it won't scroll over to the right for more than one word. This is more of an IE specific issue though, it displays fine in Firefox.

Monday, November 26, 2007

Assigning custom data types to new columns during migration

The set of data types that you can assign to a new column during a database migration is pretty limited. However, it's easy to set a column to a data type specific to the database that you're using. Instead of specifying :string, :integer, etc for the data type, specify :"data type". As an example, if you have MySQL and you want to add an unsigned integer, there's no way to specify a :integer to be unsigned. But you can do this:
add_column :table, :newcolumn, :"int (10) unsigned"

Creating/deleting foreign keys during migrations

As far as I know, Rails doesn't use foreign key declarations in your database tables, and therefore has no way of creating and deleting foreign keys in migrations. If you want foreign keys to be added/deleted to/from your database during migration, you can do so by executing SQL statements directly during the migration. I won't go over the merits of having foreign keys, in many ways they are unnecessary with Rails but there may be reasons that you want to have them. I've created a mixin module for MySQL ONLY with two functions to add or remove a foreign key, here is the code:
# a mixin module for adding foreign keys to MySQL databases during migrations.
module ForeignKeyOps
# adds a foreign key to the table.
# Parameters:
# table_name - the name of the table to add to
# association_name - the name of the constraint to add to the database
# local_column - the column in table_name that contains the key
# foreign_table - the name of the foreign table to reference
# foreign_column - the name of the primary key in the foreign table
# options - an optional hash with additional parameters for the
# constraint. If the following hash values are present, then the
# additional constraints will be specified:
# - on_delete: specify "cascade" or "set null"
# - on_update: specify "cascade" or "set null"
def add_foreign_key(table_name, constraint_name, local_column,
foreign_table, foreign_column, options = {})
st = "ALTER TABLE #{table_name} ADD CONSTRAINT #{constraint_name} "
st += "FOREIGN KEY (#{local_column}) REFERENCES #{foreign_table} (#{foreign_column})"
if options.has_key?(:on_delete)
st += " ON DELETE #{options[:on_delete]}"
end
if options.has_key?(:on_update)
st += " ON UPDATE #{options[:on_update]}"
end
execute st
end

# removes a foreign key constraint from a table. This will NOT delete the
# column in the table, it only deletes the constraint
# Parameters:
# table_name - the name of the table to remove the foreign key contstraint
# from
# constraint_name - the name of the constraint on the table to delete
def remove_foreign_key(table_name, constraint_name)
st = "ALTER TABLE #{table_name} DROP FOREIGN KEY #{constraint_name}"
execute st
end
end
 
To use this, in add a require for this file to your migration file. Then inside of the migration class, add extend ForeignKeyOps to the beginning of the class.

As an example, say you want to add a new table to your database for phones, and each phone belongs to a user. Here is the migration code, using ForeignKeyOps:
require 'db/migrate/foreign_key_ops'
class AddPhones < ActiveRecord::Migration
extend ForeignKeyOps
def self.up
create_table :phones do |t|
t.column :account_id, :integer
t.column :name, :string
t.column :number, :string
t.column :brand, :string
end
add_foreign_key('phones', 'fk_accounts_phones', 'account_id',
'accounts', 'id')
end

def self.down
drop_table :phones
end
end
 
Again as a reminder this only works for MySQL.

Wednesday, November 21, 2007

Using select_tag to make a form select field

I had a difficult time trying to find documentation on how to use the select_tag method to generate a form select box, so I'll post here what I've discovered for how to use it. Here are the parameters:


<%= select_tag "name",
"select options",
html_options = {} %>

 
name is the id and name of the select tag. Select options can be any text, this will appear in between the <select> and </select>. However, for this to mean anything you'll want it to contain option tags. The options_for_select helper generates this for you. See the details of this in the next paragraph.

html_options is a standard hash of additional options to specify on the select tag (class, event handlers, etc.). Specifying a size will allow you to make the select element scrollable with each option in a row. If no size is specified, it is displayed as a drop-down list. The other unique option here is :multiple. Setting this to true will allow the user to select multiple options. If mulitple is set to true, the size defaults to the number of options. By default, multiple is false.

Now, back to options_for_select. The syntax is:


options_for_select(array_of_options,
array_of_selected_values = [])

 
array_of_options is an array containing the selectable options. Each element of the array can either be a string or another array. If it's a string, an option is generated whose value and displayed text are the same. Example - "1" would generate <option value="1">1</option>. If the element is an array, it must be a two element array, with the first element of this array being the text to display, and the second element being the value of the option. Example = ["value 1", "1"] would generate <option value="1">value 1</option>.

array_of_selected_values is an array containing all values that you want to be selected when the page loads, if multiple selection is allowed (see html_options). Each element should contain the option value to be selected, not the text displayed.

So, let me give an example. The Rails ERb


<%= select_tag "test",
options_for_select([["value 1", "1"],
["value 2", "2"], "3", "4"],
["1", "3"]), {:multiple => true} %>

 
generates the following HTML:

<select id="test" multiple="multiple" name="test">
<option value="1" selected="selected">value 1</option>
<option value="2">value 2</option>
<option value="3" selected="selected">3</option>
<option value="4">4</option></select>

 
This will generate a selection box 4 rows long, with 1 and 3 selected.

Note that you can also put integers as option values. However, if you do, the selected options must also be integers. If you have an option with a value of 1 (integer), but put "1" in the selected options array, option value 1 will not be selected.

Saturday, November 17, 2007

Putting DIV inside of DL breaks Internet Explorer DOM

While writing a page that extensively uses definition lists (dl), I came across a pretty bad problem with Internet Explorer (6 and 7). Each dl must be completely contained in one div, you cannot put a div inside of the dl. If you do, all of the style information from all DIV's above the DL will be lost when you close the DL. Here's an example:
<div style="font-weight: bold;">
<dl>
<dt>Term 1</dt>
<dd>Definition 1</dd>
<div style="text-align: center;">
<dt>Term 2</dt>
<dd>Deinition 2</dd>
</div>
<dt>Term 3</dt>
<dd>Definition 3</dd>
</dl>
</div>

This page will render fine in Firefox - 1 and 3 are bold but not centered, and 2 is bold and centered. Things are different in IE however. 1 is bold and not centered (correct). 2 is bold but not centered (incorrect) even though the div explicitly sets centering, and 3 is not bold (incorrect), even though it is within the DIV tag specifying bold. To get DIVs and DLs to work correctly in IE, you cannot put a DIV inside of a DL. You must make a separate definition list for every div element. Here is the above example changed to work in IE:

<div style="font-weight: bold;">
<dl>
<dt>Term 1</dt>
<dd>Definition 1</dd>
</dl>
<div style="text-align: center;">
<dl>
<dt>Term 2</dd>
<dd>Deinition 2</dd>
</dl>
</div>
<dl>
<dt>Term 3</dt>
<dd>Definition 3</dd>
</dl>
</div>

This isn't that much of a pain to do, it just took some hair pulling on my part to figure out why things were all messed up in IE. If you know of a different way to do this, or know why IE behaves this way, please post a comment.

Ruby In Steel, Ruby on Rails add on for Visual Studio

If you're a Windows Ruby on Rails developer, and you already have Visual Studio, there's an awesome add on for Visual Studio to allow Ruby on Rails development from within the Visual Studio IDE called Ruby In Steel (http://www.sapphiresteel.com/). Note this isn't a Microsoft product. It gives you the full power of Visual Studio for developing RoR apps. You can set break points (even in rhtml and rjs files), mouse over things to get their values, get popups with all of the functions that classes provide, and just about everything else that you are used to from doing C# and other .NET development. This, combined with Firebug (https://addons.mozilla.org/en-US/firefox/addon/1843) to debug Javascript on the client end, gives you a full breakpoint, code step through functionality in a GUI environment for RoR. Oh, and as a pure text editor it's awesome too, since you get the full power of Visual Studio for highlighting, snippets, etc. It works great for writing Ruby scripts too.

Before using this, I was using RadRails, and to me there's no comparison between the two. If you already have Visual Studio 2005 or higher I would highly recommend this, it makes developing RoR apps so much better. I'm not sure if it would be worth getting Visual Studio just to get this addon, but if you already have it I don't think there's another IDE for RoR that's comparable.

Does anyone else know of any other Windows RoR IDEs? What are your thoughts on them?

Welcome!

Welcome! This is the first posting for my blog. I'll be posting things that I've learned while developing Ruby on Rails web apps. The posts won't be limited to strictly Ruby on Rails, I'll also post stuff for HTML and Javascript. Post a comment for this blog if you want to get in touch with me.