Wednesday, 3 September 2008

Ruby Hashes

Ruby uses hashes a lot to pass data around, and one reason for that is that they are just so easy to use. A hash is a object that contains a number of name-value pairs; a dictionary. A hash with a single entry is created like this:
h = {name1 => value1}

In practice, the name is usually a symbol, and the value often a string, so this would be the usual format:
h = {:name1 => 'value1'}

For multiple entries, separate with commas.
h = { :name1 => 'value1', :name2 => 'value2', :name3 => 'value3' }

In method calls the curly brackets seem not to be required or even desired. This can make it seem as though the method takes several parameters rather than a single hash; I think that is deliberate.

New name-value pairs can be added
h[:newname] = 'new value'
h.store :newname, 'new value'


Values can be accessed like an array:
value = h[:name1]
h[:name1] = 'new value'
h[:name1] = nil

Some web sites suggest the last of these will delete the entry; not so! To delete, use the delete method:
h.delete(:mykey)


However, accessing the key with the value is not trivial (as far as I can see). Here are two options:
h.invert[:value1]
h.find{ |k,v| == :value1 }[0]


To determine if a hash has a certain key, do this:
h.key? :my_key


You can loop through a hash with the each method. This example outputs each name-value pair (I believe the order is arbitrary).
h.each { |x,y| puts "Name #{x} Value #{y}" }

The delete_if method iterates through the hash and removes any entry for which the block evaluates to true. Note that as with the delete_if method in Aaray, this does not conform to the convention of an explanation mark for methoids that change the original.

Useful article:
http://www.informit.com/articles/article.aspx?p=26943&seqNum=3

By the way, Rails uses HashWithIndifferentAccess, which is special as it allows strings and symbols to be used interchangeably as keys when accessing values.


Struggling with Ruby: Contents Page

Friday, 22 August 2008

Dynamic Images on Rails

You can serve images through a dedicated method (or action) in your controller, but to use the format facility, you need to register the MIME type. A lot of places say to do that in environment.rb, but leave you stranded after that. What is missing is the require you need in there too:
require 'action_controller/mime_type'

However, I now believe they are wrong (or perhaps out-of-date), and the correct place to put them is in (to ensure they work in the interactive environment):
config/initializers/mime_types.rb
For example:
Mime::Type.register "image/png", :png
Mime::Type.register "image/gif", :gif

In your controller, you can now do this (for the usual post controller example):
# GET /posts/1
# GET /posts/1.xml
# GET /posts/1.gif
# GET /posts/1.png
def show
@post = Post.find(params[:id])
respond_to do format
format.html # show.html.erb
format.xml { render :xml => @post }
format.gif { render :text => @post.get_image_as_gif.to_blob,
:status => 200, :content_type => 'image/gif' }
format.png { render :text => @post.get_image_as_png.to_blob,
:status => 200, :content_type => 'image/png' }
end
end

This will respond to a request in four ways depending on the extension, serving up an image if it ends .gif or .png. The methods for creating the images go in Post.

To embed the image in the web page (note that pages can display slightly faster if you give the size and it is good practice to provide some alt text):

<%= image_tag formatted_post_path(@post, :gif),
:size => "250x250", :alt => "Image title" %>


Using RMagic
RMagick is a Ruby interface for ImageMagick, and seems to be the biggest image drawing package for Ruby.
http://www.imagemagick.org/RMagick/doc/

Unfortunately, there is no documentation with it about using it with Rails, and precious little elsewhere. There is an example program, axes.rb, so by way of illustration, this is how to convert it for use in Rails.

1. Move the require 'RMagick' to the top of the file, as normal.
2. Wrap the program in a method, with def get_image_as_png (or whatever) at the top, and end at the bottom.
3. Edit the bottom from this:
labels.draw(canvas)
#canvas.display
canvas.write("axes.gif")
exit

To this:
labels.draw(canvas)
canvas.format = 'png'
canvas
end

If there is any problem with your code, Rails just refuses to send the image, with no error message anywhere I could find. If there is no image getting through, try using the interactive environment; it will not display images, but it will show the error messages.

Note that images have to be converted to blobs before sending. I have choosen to do that in the controller's show method above. Also, you do have to inform RMagick of your file format before invoking to_blob (get a "no decode delegate for this image format" error otherwise).

Some useful pages:
http://jeremyweiland.com/archives/49
http://nubyonrails.com/articles/dynamic-graphics-with-rails-1-2
http://macdiggs.com/2007/03/08/rmagickrvg-outputting-an-inline-image/

Colour names:
http://www.imagemagick.org/www/color.html

Using RMagick with FileColumn
FileColumn is a plug-in that makes it very easy to allow users to upload images to your site, and then display them. It uses RMagick, but this seems to lead to a name clash. I found it was necessary to use "include Magick" inside any model that I was using RMagick, rather than specifying Magick::Draw, etc., as Rails complained that the latter was un undefined constant in FileColumn otherwise. Strangely this was not the case in the controller.

Struggling with Ruby: Contents Page

Additional: If you use JRuby, you will need to use Jva to create images, see here. That page also explores in more depth how to access images in your views, relevant to RMagick images as well as Java.

Monday, 18 August 2008

The Model Part 4 - Testing

Rails sets up the skeleton for unit testing when it creates a model. The skeleton is all set to run, though it does not actually test anything, with one trivial test case. However, there are a few steps of preparation:

Set up the "test" database
You need to do this whenever you make changes to the database (any time you do a migration basically). There is a rake task that will do this for you:
rake db:test:prepare

Note: Rake also supports db:test:clone and db:test:clone_structure; what db:test:prepare does is make a good guess as to which of those is best and does that.

Set up the fixtures
Rails generates a fixtures file for each model. A fixture is a file containing entries to populate the database before running each test. If you used the references type for any attributes in your model, you will need to have a belongs_to tag in your model, so that Rails will understand these to be my_model_id rather than my_model. You will get a SQL error otherwise complaining about an unknown column name.

Correct the require
If you are using NetBeans 6.1, you need to modify the require so Rails can find the test_helper file. require 'test_helper' should be require 'test/test_helper'. This has been corrected in NetBeans 6.5.

The default test should now work. In NetBeans you can right click in the file contents (i.e., the right pane), and choose test from the menu to just unit test a single file, or right click the project in the left pane and select test to run all unit tests.

Tests
Rails creates one test file for each model. I write one test method to test one use-case of a method, but I usually put in several assertions to check that the state is what I think it is before and after the method call.

Note that tests are run alphabetically. Also, be warned that if two tests have the same name, only one will be run, and you will receive no warning that one was not.

I find unit tests often involve significantly more code that the methods they test, and so most of the bugs are in the tests. However, once the bugs are gone, and the tests are passed, you do have a lot more confidence in your code. If you decide to rewrite the code, the tests should still work fine and are an excellent way to test your rewrite.

There is an issue with how comprehensive testing should be. If you have a method that manipulates a string, should you test if with nil, objects of a variety of other classes, string objects where the class has been modified? In Java or C# most of these are irrelevant.

Testing Exceptions
Use this:
e = assert_raise(RuntimeError) { my_code_that_raises }
assert_match(/Error message here/i, e.message)

From Jason Roelofs here:
http://groups.google.com/group/ruby-talk-google/browse_thread/thread/1553af54ab8beaf7

Testing Helpers
Not really models, but they can and should be tested the same. Helpers are modules, so you just need to include them. Here is how:
require 'test/test_helper'

class AppHelperTest < ActiveSupport::TestCase

include ApplicationHelper

def test_my_helper_method
end
end


Testing private and protected methods
t is just as important to test these methods, but how do you access them from outside the class? In Ruby it is actually very easy to access private methods using the send method. This will accept your method name (as a symbol), followed by the appropriate arguments. Something like this:
assert_equal 'My expected result',
my_model.send(:my_private_method, arg1, arg2)


Tips
If you want to test your model with the parameters from a complex form, you can get Rails to build the hash for you. Throw an exception at the start of the controller method that will handle the submitted form, then, in your web browser, submit the form. Rails will hit the exception, and show an error page, which will include the POST data as a Ruby hash. Copy-and-paste into your test. Rails creates a special hash in which symbols and strings are equivalent for keys; chances are you will need to convert the strings to symbols (assuming you are accessing values with symbols).

There is an excellent series of blog pages on unit testing by Kevin Skoglund that starts here:
http://www.nullislove.com/2007/11/14/testing-in-rails-part-1-unit-testing-in-ruby/
For easy reference, part ten lists the assertions available here:
http://www.nullislove.com/2008/02/20/testing-in-rails-part-10-assertions/

Struggling with Ruby: Contents Page

Wednesday, 13 August 2008

The Model Part 3 - Interactive Rails Environment

Interactive Rails Environment (IRE)
You can test the methods in your model in an Interactive Rails Environment (IRE), just like IRb. Navigate to your project's root directory, and type:
ruby script/console

In this environment you can access all your models, and the development database (the other databases can be accessed by appending "test" or "production" as a parameter to the above).

When you are in the Rails interactive environment, you can invoke reload! after modifying your code to get Rails to notice the changes. However, if you have an object on the go, it will lose its methods (at least, all your methods; methods inherited from, say, ActiveRecord::Base will still be there).

Here is an example session:
>> p = Post.find :first
=> #
>> p.test
test
=> nil
>> reload!
Reloading...
=> true
>> p.test
NoMethodError: undefined method `test' for #<post:0xafcd578>
from c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/attribute_methods.rb:256:in `method_missing'
from (irb):4
>> p = Post.find :first
=> #<post>
>> p.test
test
=> nil

As can be seen above, the solution is to retrieve the object again after reload. The problem seems to be down to versions; the old object is an instance of the old version, which no longer exists.

See also:
http://www.spacevatican.org/2008/5/28/reload-me-reload-me-not
http://rpheath.com/posts/163-rails-tips-and-tricks-part-3

Struggling with Ruby: Contents Page

Monday, 11 August 2008

The View Part 1 - ERB and Links

Rails uses the Model-View-Controller architecture. I have already discussed the model (here) and the controller (here); today it is the turn of the view.

The render method usually (depending on the parameters, as discussed with controllers) opens up a file, parses the file through ERB, and sends the result back to the requesting web browser. There really is not much more to it than that. The only complications are HTML and control structures.

As the web browser is expecting an HTML formatted page, your ERB template must be in HTML. Generally this is split between two files - the layout and the view itself - with the layout having the header and footer (both in the HTML sense, and the generic stuff at the top and bottom of all your pages), and the view having the HTML specific to that view. You really do need a good knowledge of HTML to do anything beyond the basics, but if you can cope with Ruby, HTML is dead easy.

ERB
ERB (embedded Ruby) is a template system built into the Ruby standard library, and used by Rails. It takes a template string, and where it finds certain codes will perform Ruby processing, substituting the output of that with the codes in the template. Here is an example IRb session using ERB:

require 'ERB'
template = ERB.new 'My template is called <%= @name %>'
@name = 'Fred'
puts template.result(binding)


The first line points the interpreter to the ERB.rb file (as this is in the standard library, not the core library). The second line creates a new ERB object called template. The last line calls the results method on template. The binding parameter gives the context so the template uses the value of @name from here, rather than some other method.

ERb supports a number of tags. Your Ruby code should go between the tags.

<% %> Perform the Ruby code; no output
<%= %> Perform the Ruby code; output the result
<%=h %> Perform the Ruby code; output the HTML escaped result
<%# %> Comment (note that unlike an HTML comment this is not visible to a visitor looking at the HTML source)

A % at the begining of the line can also be used to indicate that the line is ruby code (escape with %%). This appears to not be used conventionally. Also, <%% or %%> are replaced with <% or %> respectively, presumably to make it easier to write pages about ERb.

Actually, <%=h some_ruby_code %> is a bit of a trick. It is actually a method call, for the h method. It could be written <%= h(some_ruby_code) %>; it is just the same.

Reference
http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/

ERB and Rails
Rails already includes ERB, so the require 'ERB' is not required.

The layout file, pehaps application.html.erb, must include a call to the yield method, like this:
<%= yield %>

The yield uses the view file, perhaps edit.html.erb, parsing it with ERB, and inserting the result into layout result.

All this processing is done in your controller's superclass (ActionController::Base), so the environment used (the binding) is that of the method in your controller. ERB can access any variables and methods that you can inside that method.

Links
ActionController::Base includes some methods to help with links. The link_to method will generate the HTML code for a simple link, as in this example:
<%= link_to 'New post', new_post_path %>


"New post" is the text that will appear in the link. The method new_post_path will generate the URL on the fly (and will take into account the current URL; if the web browser is at http://mydomain.com/, your page will require a different URL to http://mydomain.com/posts/index).

As well as link_to there are also button_to, link_to_if and link_to_unless methods.

API for link_to (with links to alternatives)
http://www.railsapi.org:8100/actionview-helpers-urlhelper-link_to

Saturday, 26 July 2008

Ruby Strings

Java and C# take the view that strings are fundamental to the language and that API users should be able to rely on them doing exactly what is expected, and so the String class is set in stone, and each instance of String is immutable. Ruby takes the other road, allowing the user to do whatever he wants with a string. The Ruby way is certainly more convenient; whether there are security implications I am not sure (though unlike Java and C#, Ruby is not targetted at running within a web page).

API documentation:
http://www.ruby-doc.org/core/classes/String.html

There are a surprisingly large number of ways of defining a string in Ruby.

Double-quoted: Uses backslash escapes (like C, etc.), and embedding variables and code with #{some_code} (use \# for a hash).

%Q notation: %Q/My text/ is almost the same as "My text", or %Q[My text] or %Q@My text@ or whatever (not letters or numbers!). You can use a backslash to include your terminating chartacter, eg %Q!This is important\! Really it is.!.

Single-quoted: No escapes (except \' for a single quote). Single quoted strings require less processing than double quoted, though I suspect the difference is insignificant.

%q notation: %q/My text/ is almost the same as 'My text'.

Return
If you include a return in your string (i.e., it goes on to multiple lines), that gets converted into a return!
s = "First
Second"
p s # => "First\nSecond"

On Windows a return is \n (as in Java, and as opposed to C# which defaults to \r\n).

Concatenating and appending
Concatenation as in Java and C#
a = "first string" + " second string"
# => a = "first string second string"
a += " third string"
# => a = "first string second string third string"


But with an append method too.
a << " third string"
# => a = "first string second string third string"

This is the more efficient way (+= creates a new string from the two parts).

Note that using << to add an integer between 0 and 255 adds the character (this is because Ruby does not have a character type as such).
a = "hello"
a << 72 # a is "helloH"

Adding other numbers generates an error. This is one place that Java and C# beat Ruby; they can cope with adding numbers (and indeed any class) to a string without an explicit conversion.

Repetition (how is that useful exactly?)
a = "repeated " * 4
# => "repeated repeated repeated repeated "


Extracting bits
Extract characters as though it is an array
a[n]     # the nth character (starting from zero)
a[-n] # the nth character from the end (starting from 1)
a[n..m] # a substring from n to m (same as a[n,m]
a[n...m] # a substring from n to m-1
a[n] # The ASCII value of the character
a[n].chr # The actual character

Note that a[n..m] is perfectly happy with variable names rather than specific numbers.

You can also replace chunks in a similar manner.
s = "Here is short string"
# => "Here is short string"
s['short'] = 'long'
# => "long"
s
# => "Here is long string"

It only replaces the first occurance, but can accept regex expressions.

Methods
A list of string methods from here:
http://www.wellho.net/solutions/ruby-string-functions-in-ruby.html

To change case:
capitalize - first character to upper, rest to lower
downcase - all to lower caseswapcase - changes the case of all letters
upcase - all to upper case

To rejustify:
center - add white space padding to center string
ljust - pads string, left justified
rjust - pads string, right justified

To trim:
chop - remove last character
chomp - remove trailing line separators
squeeze - reduces successive equal characters to singles
strip - deletes leading and trailing white space

To examine:
count - return a count of matches
empty? - returns true if empty
include? - is a specified target string present in the source?
index - return the position of one string in another
length or size - return the length of a string
rindex - returns the last position of one string in another
slice - returns a partial string

To encode and alter:
crypt - password encryption
delete - delete an intersection
dump - adds extra \ characters to escape specials
hex - takes string as hex digits and returns number
next or succ - successive or next string (eg ba -> bb)
oct - take string as octal digits and returns number
replace - replace one string with another
reverse - turns the string around
slice! - DELETES a partial string and returns the part deleted
split - returns an array of partial strings exploded at separator (eg, s.split(/_/) )
sum - returns a checksum of the string
to_f and to_i - return string converted to float and integer
tr - to map all occurrences of specified char(s) to other char(s)
tr_s - as tr, then squeeze out resultant duplicates
unpack - to extract from a string into an array using a template

To iterate:
each - process each character in turn
each_line - process each line in a string
each_byte - process each byte in turn
upto - iterate through successive strings (see "next" above)

One that I find partuicularly useful is split, which will break a string into an array of substrings, breaking at the characters you specify (either a string or a regex; defaults to whitespace):
s = "Here is a\nstring"
# => "Here is a\nstring"
s.split
# => ["Here", "is", "a", "string"]
s.split(/a|e|i|o|u/)
# => ["H", "r", " ", "s ", "\nstr", "ng"]


Also interesting is scan, which kind of does the opposite of split. Again it returns an array, but this time of the text that matches, rather than the text between the matches. This one example will return an array of links from an HTML document:
links = content.scan(/<a .+?<\/a>/i)


System commands
A back quoted string (eg `dir`) gets sent as a command to the OS. The system method in Kernal does similar (eg, system dir). You can also use %x[], for example, %x[dir].

Here Document
A "here document" is yet another form of string, designed for large one-off chunks of text (mm, not good for internationalisation). It is denoted by <<, followed by the terminator.
a = <<END
Some text
END

b = <<-NONSENSE
The hyphen allows the terminator to be indented
NONSENSE

do_stuff(<<TERMI, other_parameters
This text will all
go into the method as the
first parameter
TERMI

You can do operations directly on your here document, as shown here:
p(<<-EOS.reverse)
This is my string
EOS
# => "\ngnirts ym si sihT "


Formated String
You can also generate a formated string with the % operator, which is more or less equivalent to the sprintf method. One difference is that the % operator requires an array for multiple substitutions.
"%d" % 12
sprintf "%d", 12
# => "12"
"x = %04d, y = %s, z = %.2f" % [12, "value", 1.234]
sprintf "x = %04d, y = %s, z = %.2f", 12, "value", 1.234
# => "x = 0012, y = value, z = 1.23"
x = 1.12345
n = 2
"%.#{n}f" % x
sprintf "%.#{n}f", x
# => 1.12

What is useful about this is that you can pass your format string around, and apply the subsitutions to it multiple times.
a = "x = %04d, y = %s, z = %.2f"
c = a % [12, "value", 1.234]
# c is "x = 0012, y = value, z = 1.23"
c = a % [42, "other value", -11.2]
# now c is "x = 0042, y = other value, z = -11.20"


Templates
From here:
http://freshmeat.net/articles/view/447/

This useful technique will go through the template string, substituting any occurance of something inside :::, with the string in the hash, values, as determined by the names in the hash
templateStr.gsub( /:::(.*?):::/ ) { values[ $1 ].to_str }

For more complex template usage, Ruby has ERB (see here).

Other Manipulations
Rails offers a variety of new methods for changing strings, including pluralize and tableize; methods used by Rails to convert between table names, class names and filenames.
http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html

Here is a way to split camel case into title case:
"MyCamelCaseClassName".split(/(?=[A-Z])/).join(" ")
# => "My Camel Case Class Name"


Struggling with Ruby: Contents Page

Tuesday, 22 July 2008

The Controller Part 3 - Render and Filter

Ruby on Rails uses the MVC archetecture for web applications. This post is the last of three posts about the controller part, focusing on the rendering and filters.

Render
The render directive is used to generate a web page, typically a view.

Render has several options. Render defaults to the view with the method name, in the folder with the name of the current controller, using the layout with the controller name if it exists, or the application layout otherwise. In the Edit method of PostsController , these two are equivalent:
render
render :action => 'edit', :layout => 'posts'

Indeed, even the word render is unnecessary; Rails will default to the above even if no render directive is present, as seen in the Edit method of PostsController (behind the scenes Rails has a variable that notes when a render has been done, to ensure one gets done even if not specified, and to throw an error if you try to do it twice).

Render has several options.
:action  # Render using the view app/views/[controller]/[action].html.erb
# (note that the action named need not exist in any controller)

:template # As :action, but using the file app/views/[template].html.erb.
# Use this for consistent views between controllers.

:file # Render the given file (needs the absolute path, which seems a
# bit of a drawback to me). Layout not used.

:text # Render the given text as the web page. Strangely, you can use
# this to return an image (render :text => image.to_blob).

:inline # As text, but ERb is parsed.

:partial # Render as a partial web page (can be updated while the rest
# of the web page remains).

:nothing # Return a web page with no content.

:status # The HTTP code to be returned (returning :status => :success
# with :text causes an error, and it seems to be ignored for :action).

:content_type # For an image, this mght be :content_type => 'image/gif'

# My attempts to change the controller failed; it was just ignored.
# I had hoped to reuse the view of another controller; use template
# to do that instead!

More on render:
http://api.rubyonrails.org/classes/ActionController/Base.html#M000848

Filters
Filters are directives to perform certain methods before or after every action. A before_filter might be used to ensure a user has been authenticated, or for logging purposes, for instance.

Filters should appear at the start of the class, in the form:
before_filter :my_filter

Set up my_filter like any normal method. If it returns a Boolean false, the action will be aborted. Alternatively, your filter could initiate a redirect (say, pointing the user to the login page).

There are several different flavours of filters:
before_filter
prepend_before_filter # Do this filter before
other before filters
append_before_filter # Do this filter after other
before filters
after_filter
prepend_after_filter
append_after_filter
around_filter # use the yield keyword in the
filter when the output would go. Useful for
capturing exceptions
prepend_around_filter
append_around_filter
skip_filter # Want to skip filters in a superclass?

Filters apply to all actions in your controller (or all actions in your application if they are in ApplicationController). However, you can limit them:
:only => :edit # Apply this filter to the edit action only
:except => [:new, :delete] # Do not apply to the :new or :delete actions

Reference
http://api.rubyonrails.com/classes/ActionController/Filters/ClassMethods.html

This site uses a filter to avoid repetitive loading of objects
http://manuscripttranscription.blogspot.com/2007/06/rails-short-introduction-to.html

Using a Filter to Test if a Record Exists
The find method of ActiveRecord will throw an exception if no record is found with that ID. This can happen even if your web app is perfect, for example when the user makes a mistake typing in a URL directly (as Rails interprates any unknown as being an ID). How do you handle that?

You have three choices. All the examples I have come across just ignore it. Let Rails throw the exception, and deal with it itself. In the development environment this means giving a web page with a stack trace; in the production environment a page is displayed telling the user that the administrator has been informed of the problem. A better solution is to catch the exception and handle it yourself, giving the user a more helpful result that does not leave the impression that your software is buggy!

However, my prefered solution is to avoid the exception altogether, by testing whether the record exists before trying to retrieve. And the best place to do that is in a before_filter. You might set the filter up like this (note that these are just the typical methods that retrieve a specific record by ID):
before_filter :check_id, :only =>
[ :edit, :update, :destroy, :show]

Then you include the method (which should be protected, so it cannot be called as an action):
  protected
def check_id
return if Post.exists? params[:id]
@ref = params[:id]
render :action => 'no_show'
end

This simply checks the record exists, and if not renders an alternative page.

Struggling with Ruby: Contents Page