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

Monday, 21 July 2008

The Controller Part 2 - Basic Methods

Ruby on Rails uses the MVC archetecture for web applications. This post is the second of three posts about the controller part (part one here), looking at what goes inside the controller file.
Consider the usual scenario - a web log - with a model, called post, and a corresponding controller. The posts_controller file is where the PostsController class is defined. More specifically, this is where you put the methods that correspond to your actions. If you want a show action (responding to http://localhost:3000/posts/show/5), then you need a show method.

Actions that cause changes to the database table will generally require two methods. One to display the form that the user will make the changes on, and one that is invoked when the form is submitted, updating the table. The two standard sets are new and create, and edit and update. I will examine the edit and update that are generated by Rails in a typical web log application. The edit method produces a page with a form that the user can fill in. He hits Submit, and his HTTP request is pointed to the update method.
# GET /posts/1/edit
def edit
@post = Post.find(params[:id])
end


# PUT /posts/1
# PUT /posts/1.xml
def update
@post = Post.find(params[:id])
respond_to do format
if @post.update_attributes(params[:post])
flash[:notice] = 'Successfully updated.'
format.html { redirect_to(@post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @post.errors,
:status => :unprocessable_entity }
end
end
end

Methods in the controller generally seem to revolve around collecting data, and then rendering it, and these are no exception (the edit method has an implicit render command). Let us look at them a little more closely.

Collecting Data
The edit method creates an instance variable @post. Its value is an object of the Post class with the relevant id. Any data that you want to display on your page must be put into instance variables at this point. If you want to populate a drop-down list with values from another table, you must assign those values to an instance variable here. If you want to welcome the user by name, you must assign the name to an instance variable here.

Numerous times this will involve searching a particular table, and Ruby on Rails offers a lot of help. The simple find method locates a record by id, but you can also search by any column
Post.find 12 # Gets the post with ID equal to 12
Post.find 2, 4, 5 # Gets the posts 2, 4 and 5
Post.find_all # Gets all the posts
Post.find_all :order => 'author', :offset => 20,
:limit => 10 # Gets the 21st through to 30th
# posts (or possibly 20 to 29), ordered by author
Post.find_by_title 'My First Blog Page'
# Gets the post with the given title
Post.find_all_by_author 'F2Andy'
# Gets an array of posts where the author is F2Andy
Post.find :all, conditions => {
:title => 'My First Blog Page', :author => 'F2Andy'}
# Finds all posts fulfilling both conditions
Post.find :all, conditions => [
'title LIKE :title AND author = :author', {
:title => 'Blog', :author => 'F2Andy'}]
# Finds all posts fulfilling the SQL conditions


Reference:
http://api.rubyonrails.org/classes/ActiveRecord/Base.html

See also this on find_by_sql
http://www.edwardthomson.com/blog/2007/02/complex_sql_queries_with_rails.html

By the way, named_scopes offer a way to get frequently used subsets of records from a model.

Turning to the update method, this is invoked when the user submits the form with the new data. The new values for the post are held in the hash, params[:post], and obviously we want to overwrite the old values. This is done with the update_attributes method in the Post class (actually the method is in the superclass). This saves the data to the database, returning true if successful (e.g., the data was validated successfully).

Rendering
This means we have two possible outcomes, and the resultant web page has to reflect that. The code also allows for an XML request, using the respond_to facility. The format goes into the variable format, and the rendering is determined by whether the update was successful, and whether the format should be HTML or XML. Here is the XML part from the show method:

format.xml { render :xml => @post.to_xml }

What this means is that what is returned to the web browser is the result of @post.to_xml. The to_xml method will automatically create an XML string for your model. This probably does not make much sense when your application goes beynd CRUD, and you either need to think carefully about what should be returned or not respond to XML at all.

Rails maintains a variable called flash for one response (redirectings are not counted). This is used to hold alerts, keeping the user informed. If the update was successful, this is therefore noted in flash[:notice]. Errors are reported in flash[:error]; why does Rails not do this by default?

More on responds_to:
http://weblog.jamisbuck.org/2006/3/27/web-services-rails-style

A successful update and an HTML response requested results in a redirect_to. The redirect_to method sends an HTTP 302 code to the requester, redirecting him to a new page. You can specify the controller and action for the redirect, but in this case the redirect is to @post, which Rails will handle as a request to show this post.

I will discuss rendering more in the next post.

Struggling with Ruby: Contents Page

Thursday, 17 July 2008

The Controller Part 1 - Routing

Ruby on Rails uses the MVC architecture for web applications. This post is the first of three posts about the controller part, and is a quick look at routing.

The web log (blog) seems to be the archetypal Rails application, so in keeping with tradition, let us look at the controller for the posts model in a blog. This will be in a file called posts_controller, and a class called PostsController.

PostsController is a subclass of ApplicationController, a class generated in your application, in the file application.rb, by Rails when you created the project. This means you can make changes to ApplicationController and they will affect all the controllers in your application (and methods in application_helper.rb are available to all controllers, but not models).

ApplicationController is itself a subclass of the Base class in the ActionController module. You can find it in [ruby]\lib\ruby\gems\1.8\gems\actionpack-2.1.0\lib\action_controller\base.rb, however, this is not part of your application, and should never be modified. Base does a lot of the hard work so you do not have to.

Handling a request
Routing is configured through the routes.rb file. There is no class defined in the file (though in common with other classless Ruby files it automatically becomes part of some class to maintain the object-orientated paradigm), just Ruby code. The first line is:
ActionController::Routing::Routes.draw do map

What this does is invoke the draw method in the ActionController::Routing::Routes class, with each of the listed map entities. Each subsequent line in routes.rb (that has code on it) specifies a route to be mapped. When the web server receives a request, it checks the URL against the mapped routes, using the first one that matches, or returning a 404 "page not found" if none do (if public/index.html exists, this gets priority over any mapping for the root, usually http://localhost:3000/ during development).

The routes.rb file seems to be read for each request. Some changes made to the file will be acted on for the next request; however, some settings are not (eg map.resources), and require the web server to be restarted before they take effect.

The Rails generators handle default settings in routes.rb (you might want to set map.root though), and there are helpful comments in there too.

Rails will put in something like this (after a generate scaffold):
map.resouces :posts

This sets up some basic routing rules, allowing the usual RESTful operations (those created by scaffold, new, show, etc.).

Say your web server received a GET request like this:
http://localhost:3000/posts/show/5

The web server will take "posts" to indicate the controller. In this case it would look for the PostsController, and it will assume that that will be in the file posts_controller.rb. It will look through the methods in PostsController for a public method called either "show" or "5", and will invoke that method, using the other value as the value for the ID. Obviously it will find a show method, so it will take 5 as the ID.

In the absence of a method name in the URL, the web server will default to show, so this will do the same as the previous URL:
http://localhost:3000/posts/5

That presents a problem for pages that have no ID. For example, you might have a search page, and you would want to access it from this URL:
http://localhost:3000/posts/search

Unfortunately, the router will believe that it is the method missing, not the ID, and will complain that there is no post with £search" as the ID to show. We have to explicitly tell the router to expect pages that have no ID, which we can do like this:
map.resources :posts, :collection => {:search => :get, :options => :put}

In this example, two pages are added to the routes, search and options. The search page is set as an HTTP GET, and he options as an HTTP PUT.

Earlier versions of Rails (and of this page) have required that all pages outside the standard CRUD operations get declared in this way; pages that use an ID were assigned to :member, rather than :collection.

Data is sent from a web page form in the params hash, which includes the action, controller and id as above, as well as a hash of the data on your form, named as per your form (normally the name of the controller). In this example, a hash of the data from the form for a post would be accessed by params[:post]. To access a single value in the form hash, use something like params[:post][:title]

See also:
http://api.rubyonrails.org/classes/ActionController/Resources.html
http://api.rubyonrails.org/classes/ActionController/Routing.html

Struggling with Ruby: Contents Page

Monday, 14 July 2008

Ruby Methods Part 3 - The method_missing method

When you invoke a method on a class, the Ruby interpreter searches through the class hierarchy for a method of the given name, and if it fails it will invoke the method_missing method. This method is in the Kernel module, and so is accessible to the Object class, and hence to all objects. The method simply throws a NoMethodError. However subclasses can override it, to do something useful. You can write a method_missing method which will catch any unknown method calls, and decide what to do with them.

This example simply lists the parameters - the first is the invoked method name:
def method_missing *args
puts "method_missing:"
args.each { x
puts x
}
end

Or this version explicitly pulls out the method name in the parameter list:
def method_missing method_id, *args
puts "method_missing: " + method_id.to_s
args.each { x
puts x
}
end

Rails uses this to handle the find_by_[column] method calls, for instance, checking if the method call starts find_by_ and ends with a column name, throwing an exception if not.

Note that method_missing is entirely different to self.method_missing. The former handles unknown instance method calls, the latter for unknown class method calls.

You can override method_missing in a superclass in your own class. If the method call fails to match what you were expecting, you can pass the responsibility on to the superclass, using the super keyword.
def method_missing *args
if matches args[0].to_s
do_stuff
else
super
end
end

super can cope with def method_missing *args or def method_missing method_id, *args

Trying to invoke an unknown method in method_missing will cause a stack overflow!

This web page makes a good case for moving method_missing to a new class dedicated to dynamically handling method calls:
http://blog.jayfields.com/2008/03/ruby-isolate-dynamic-receptor.html

Struggling with Ruby: Contents Page

Thursday, 10 July 2008

The Model Part 2 - Validation and Association

Last time around I was looking at what the model is, now I will look at the actual code.

The model class file could be as simple as:

class MyModel < ActiveRecord::Base

end


The superclass, Base in module ActiveRecord, handles all the SQL and more besides, and for simple applications that is all you might need. Often you want more, though, and there are broadly three things you might include. These are validation, association and actual ruby code to define your class behaviour.

Validating input
There are several validating methods available. They are used like this:
validates_presence_of :attribute1, :attribute2

By including one or more of these in your model, you will ensure that all data going into the model is valid, according to that requirement. In the example above, Rails will only allow the model to be updated with the new data if both attribute1 and attribute2 are present. Other options:
validates_acceptance_of
validates_associated
validates_confirmation_of
validates_each
validates_exclusion_of
validates_format_of
validates_inclusion_of
validates_length_of
validates_numericality_of
validates_presence_of
validates_size_of
validates_uniqueness_of

For the most part they are very easy to use. Here, the field is only valid if there is no record with the same value for that field already in the database:
validates_uniqueness_of :sample_reference

A bit more complex, this will check the field conforms to a certain pattern:
validates_format_of :sample_reference, :with => /^(P|L)\d\d\d\d\d$/

You can also do it all yourself. This example ensures there are no question marks in the description field:
validate do |sample|
sample.errors.add(:description, "replace ?") if sample.description.include? '?'
end

Note that errors go to the errors object in your record. Use add to attach the error to a specific attribute, or add_to_base otherwise.

Also note that update_attributes (used by the update method in your controller) also checks validation, returning false if validation fails. It may not be give any clue about why it failed (which can lead to very mysterious errors during testing).

Another point; this is a block, not a method that you are defining. If you use return in there, it will give some strange behaviour as Ruby attempts to return from the method that invoked the block (at least, I assume that is why you get the strange behaviour).

For more details go here:
http://railsapi.org/ActiveRecord::Validations::ClassMethods


Associations
Associations are a way to connect two or more tables in a database. They are done through class methods in Activeecord::Base, just like validations. Associations can be many-to-one, one-to-one or many-to-many.

Let us suppose we have two models - model1 and model2 - where model2 can be associated with any number of model1. By convention, model1 will have a column model2_id.

model1
In the model definition you need this to associate it with model2:
belongs_to :model2
You can now access model2 like this.
model1.model2

model2
In the model definition you need this to associate it with model1:
has_many :model1s # note the plural
You can now access model1 like this.
model2.model1s

model1s is an array (effectively), and you can use and manipulate it in the normal way (but see here for a neat filtering trick that you can not do on a real array).

For a one-to-one relationship, you can use this:
has_one :model1

Again, model1 will need a field model2_id for this to work. Having said that, model2_id is just the default name. You can use your own name with the foreign_key option.
has_many :model1s, :foreign_key => 'id_of_model2'

I would guess you need that for both the has_many and the belongs_to?

Reference:
http://en.wikibooks.org/wiki/Ruby_on_Rails/ActiveRecord/Associations
http://www.jumbabox.com/2008/06/ruby-on-rails-one-to-many-tutorial/

through
A through association allows model2 to access model0 via model1
has_many :model1
has_many :model0, :through => model1
Now you can now access model0 like this.
model2.model0s

Reference:
http://wiki.rubyonrails.org/rails/pages/ThroughAssociations

Note: There are issues with validation if the parent has not been saved
http://macksmind.net/2008/04/26/using-belongs_to-in-rails-model-validations-when-the-parent-is-unsaved/

polymorphic
The polymorphic option allows you to associate a model with different classes of models, either though the class inheritance (i.e., model1 can be associated with model2 or any of its subclasses) or using the "as" option.

The "as" option sets up an interface (in the background; no need for you to worry about that):
belongs_to :my_interface, :polymorphic => true
has_many :model1s, :as => :my_interface

many-to-many
I have yet to try this, but here is an interesting page:
http://www.jumbabox.com/2008/06/ruby-on-rails-many-to-many-tutorial/

Ruby Code
The last thing you might want to put in your model (that I know about!) is Ruby code to define the behavior of the object. There is an issue here about what goes in the model and what goes into the controller. Methods invoking the object go in ther model, methods involved in controlling the web site go into the controller. In general, I try to put everything I can into the model, as it is easier to test.

Struggling with Ruby: Contents Page

Wednesday, 9 July 2008

The Model Part 1 - Creation

The Ruby on Rails design pattern is the model-view-controller.
http://api.rubyonrails.com/classes/ActiveRecord/Base.html

The model is the connection to the database, but it is also the class (in an OO sense) representing your data. Any methods that would go inside the class, should go into the model.

Creating a Model
Rails can create a model in any of four ways. If you also want a controller and default views (for basic CRUD operations; new, show, edit and delete), generate a scaffold. If you want a blank controller with your model so you can create your own views, generate a resource. Otherwise you can generate a model, say if you just want a table to populate a drop-down list. Finally, you can just create a new file, and code it directly, of course.

The model name should be something appropriate, in the singular, either in CamelCase or under_scored lowercase. The generated files and classes will be named (Ruby on Rails has a built-in function for deriving plurals):
you named it: BlogPost or blog_post
database table: blog_posts
model class name: BlogPost
model class file: blog_post.rb
model class test file: blog_post_test.rb
controller class name: BlogPostController
controller class file: blog_posts_controller.rb
controller functional test file: blog_posts_controller_test.rb
views folder: blog_posts

The options are a space separated list of attributes, like this:
name:string body:text post:references

Note that an ID column and time stamp columns are automatically added (the latter note creation and last modified date and time).

The "references" type in the example allows you to relate your table to another table. If you have several comments in a blog for one post, then each comment references the post. Rails will generate a post_id column. This means you should create the parent model, before the child (posts before comment). To get this to work properly, you need to associate the child model with the parent with a belongs_to - more on that in a later post.

The types allowed are:
:primary_key, :string, :text, :integer, :float, :decimal,
:datetime, :timestamp, :time, :date, :binary, :boolean


Some examples
ruby script/generate scaffold BlogPost name:string body:text
ruby script/generate resource BlogComment body:text post:references
ruby script/generate model User
Column names to avoid: Rails will generate a method with the name of your columns, so you are firstly restricted to lowercase letters, digits (but not at the start) and underscore. Furthermore, you should avoid any existing method names, as there will be a conflict. Others to avoid are: type (used by Rails in Single Table Inheriance to hold the classname), graph (seems to throw PostgreSQL; but not MySql). I would also avoid these: timestamp, data, time, number, text, date.

More here:
http://api.rubyonrails.com/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html

Once the model is generated, migrate to the current database version.

Modifying a Model's Columns
You can do this through a generated database migration, or revert your database back, edit your existing migration, and then migrate back to the current version. The latter keeps the number of migrations to a minimum, but could lead to other problems, especially if others working on the project are not using the new version. *

If you choose to use a database migration to add a new column, you need to give the migration a name that includes the table name, such as AddCategoryToPosts.
ruby script/generate migration AddCategoryToPosts

The migration file produced is quite different to the file used to create a new table, as it uses the add_column method, as opposed to the create_table method. This seems to preclude the references type (though I could be wrong about that), so you would have to do:

post_id:integer

Try to get it right from the start!

Reference for migrations:
http://wiki.rubyonrails.org/rails/pages/UsingMigrations

Part 2 will look at the code inside the model.rb file.

Struggling with Ruby: Contents Page

Monday, 7 July 2008

Building a Basic Project

This is a brief overview of creating a Rails project. There are plenty of alternatives out there, but I felt there would be something missing if I skipped this.

A Ruby on Rails application revolves around the MVC model. In this design pattern each table in the database corresponds to a model. The model is a class (in the object-orientated sense) that inherits from ActiveRecord, and ActiveRecord handles all the basic database interactions. It is quite possible that your model will have no code in it at all.

For each model, there is usually one controller. The controller accepts the requests from the user, and decides how they will be handled.

For each controller they may be a number of views. Each view is a web page template (rather than a ruby program as such), invoked as a response by the controller.

Rails provides a way to generate the bare bones very easily - this is is big strength. Once you get outside the simple web application, Ruby provides the flexibility to allow you to do anything, but suddenly it gets much more complicated. So forget that for now...

To build a simple web application in NetBeans 6.1:
File - New Project
This builds the directory structure.

Create database (you need MySql running and connected at this point):
Right click your project name: Run Rake Task - db - create

Create the scaffold (the bare bones of your MVC system for one table)
Right click your project name: Project -> Generate Generate: scaffold
In the dialogue box put in the model name, that is the name of the table, in the singular, in CamelCase. For the attribute pairs, these are the column names with the type, for example:
title:string

You can put in as many as you want (over twenty anyway), separated by spaces. Types include: string, text, integer, references. Click okay, and Rails will create your model, controller and some default views for doing basic CRUD operations.

The next step is to migrate your database. Rails will only generate a file that specifies the table, this step gets that specification into the SQL database.
Right click your project name: Migrate Database - To Current Version

At this point, the web server can be run, and entries added, etc.

My next few posts will look more at the model, the controller and the views.

Note 1: The official NetBeans tutorial has the scaffold generated before the database is created. Either way works, but their way leads one to think the scaoffolds are generated once per project, like database creation. In fact you can generate numerous scaffolds.

Struggling with Ruby: Contents Page

Sunday, 6 July 2008

Starting Ruby...

I have recently started to learn Ruby on Rails, and this blog is by way of documenting that process. I am only a hobbiest coder, learning for fun, so progress may well be slow. However, one thing I have learnt so far is that the amount of readily available information is not great, compared to other languages that I have learnt (Java and C#). In part, this is because the language is not stable, Rails 2.0 is only six months old, and the number of tutorials for 2.0 is few indeed (and there is not the backwards compatibility in Ruby/Rails that there is in Java, for instance).

So part of my purpose is to fill that gap. Even if no one else reads this blog, at least I will have documented what I have found for myself.

For a list of posts ordered by topic, go here:
http://strugglingwithruby.blogspot.com/2008/11/contents-page.html

What is Ruby on Rails?
Ruby is a dynamic, object-orientated programming language. Ruby can be readily extended using "gems", plugins written by third parties. Rails is one such plug. Rails makes it very easy to create a bare-bones web application that interfaces with a database.

To install Ruby go here (also includes how to instal Rails):
http://www.rubyonrails.org/down

Installing gems locally:
Change to the directory the gem is in (the .gem file), and type:
gem install -l

I am using NetBeans 6.1 for my IDE, as I am used to it from Java (and it is free).
http://www.netbeans.org/

My Project
I am having a go at creating a galactic conquest game, StarEmpire, using Ruby on Rails. Whether it will see the light of day, I do not know, but I anticipate learning a lot along the way. This would be a multi-player game, with each player marshalling starships and worlds to achieve galactic domination. Some of the challenges include user authentication and generating images on the fly.

Struggling with Ruby: Contents Page