more info

Media72 Hosting Articles and Tips

Archive for the 'Contributors' Category

Howto: Write a plug-in

Wednesday, January 16th, 2008

In my previous post, I listed 6 things that you should try in Rails. I also promised some example code to get you started. Since I have already covered installing and upgrading rails, the next cab off the rank is writing a plug-in.

Plug-ins are fantastic - they allow you to abstract away common code into nice little bundles that you can re-use on other projects. Rails even has a built-in system for downloading other peoples plug-ins straight from their SVN repository. With the change over to Rails 2.0, some used-to-be-core functionality has been moved into plug-ins, to clean up the core tree and to allow other developers to release new versions of the plug-ins outside of the regular Rails release cycles.

In this (very brief) tutorial, we will create a plug-in called acts_as_blabbermouth that will print out random quotes . Obviously this plug-in is of little use in the real world, but it should act as a nice demonstration of how plug-ins work.

It’s really easy to generate the boilerplate code thanks to the generate script. To start your plug-in, run the following command in the root of your Rails app:


script/generate plugin acts_as_blabbermouth

You should see an output similar to this:


create  vendor/plugins/acts_as_blabbermouth/lib
create  vendor/plugins/acts_as_blabbermouth/tasks
create  vendor/plugins/acts_as_blabbermouth/test
create  vendor/plugins/acts_as_blabbermouth/README
create  vendor/plugins/acts_as_blabbermouth/MIT-LICENSE
create  vendor/plugins/acts_as_blabbermouth/Rakefile
create  vendor/plugins/acts_as_blabbermouth/init.rb
create  vendor/plugins/acts_as_blabbermouth/install.rb
create  vendor/plugins/acts_as_blabbermouth/uninstall.rb
create  vendor/plugins/acts_as_blabbermouth/lib/acts_as_blabbermouth.rb
create  vendor/plugins/acts_as_blabbermouth/tasks/acts_as_blabbermouth_tasks.rake
create  vendor/plugins/acts_as_blabbermouth/test/acts_as_blabbermouth_test.rb

As you can see, all of the boilerplate code has been created in the vendor/plugins/acts_as_blabbermouth directory.

The README and MIT-LICENSE are just generic text files that you should fill out - generally, the README file is the first place a new user will look for instructions on the plug-in.

The lib directory will hold the guts of your plugiin. The tasks directory is a place where you can store any rake tasks that your plug-in might need. The tests directory is, well, pretty self explanatory - just as you can test your Rails app, you can test your plug-in too. The install.rb and uninstall.rb files are called when installing and uninstalling your plug-in - you can place code here to initialize your environment and to cleanup after yourself. Finally, init.rb is the file that Rails actually calls to load your plug-in.

The main file we have to worry about is /lib/acts_as_blabbermouth.rb - this is where our main code will go.

Firstly, we need to include the acts_as_blabbermouth.rb file into the environment. This is done by adding the following line to the init.rb file:


require File.dirname(__FILE__) + '/lib/acts_as_blabbermouth'

Next, we add the following code to lib/acts_as_blabbermouth.rb


# ActsAsBlabbermouth
module ActiveRecord #:nodoc:
  module Acts #:nodoc:
    module Blabbermouth #:nodoc:
      def self.included(base)
        base.extend(ClassMethods)
      end

      module ClassMethods
        def acts_as_blabbermouth
          include ActiveRecord::Acts::Blabbermouth::InstanceMethods
          extend ActiveRecord::Acts::Blabbermouth::SingletonMethods
        end
      end

      module SingletonMethods
        def quote_me
          quotes = [
            "When you come to a fork in the road, take it. -Yogi Berra",
            "Every child is an artist. The problem is how to remain an artist once he grows up. -Pablo Picasso",
            "What we anticipate seldom occurs; what we least expected generally happens. -Benjamin Disraeli",
            "Drive-in banks were established so most of the cars today could see their real owners. -E. Joseph Cossman",
            "The greatest pleasure in life is doing what people say you cannot do. -Walter Bagehot"
          ]

          quotes[rand(quotes.size)]
        end
      end

      module InstanceMethods
        def quote_me
          self.class.quote_me
        end
      end
    end
  end
end

ActiveRecord::Base.send(:include, ActiveRecord::Acts::Blabbermouth)


Now, create a model file called quote.rb by running


script/generate model quote

and add the following line after the class declaration and before the end declaration


acts_as_blabbermouth

Fire up the script/console and type:

Quote.quote_me

Voila! If all went to plan, you should see one of the random quotes. Congratulations! You just wrote a plug-in!

So how did we do it?

  1. We drilled down in to the ActiveRecord::Acts module and mixed in a module called Blabbermouth. This acts like a namespace in other languages, so we can create our own set of classes and methods without stomping on other peoples plug-ins.
  2. We override the included class method, which gets called when the plug-in gets mixed in to another module. Here, we include the ClassMethods module, which exposes the acts_as_blabbermouth method to the model class
  3. We define the acts_as_blabbermouth method. All this method does is include the InstanceMethods and SingletonMethods modules. The InstanceMethods module contains all of the methods available on an instantiated object and SingletonMethods contains all the methods available to the un-instantiated class.
  4. We create a SingletonMethod called quote_me, which returns the random quote. This can be called by calling Quote.quote_me. We also create a method called quote_me in the InstanceMethods module, which calls the SingletonMethod - this way both the class and the object can call the quote_me method.
  5. Finally, we call ActiveRecord::Base.send(:include, ActiveRecord::Acts::Blabbermouth) which tells the ActiveRecord::Base module to include the code we have written.

For those of you playing at home, I’ve attached the plug-in source in a tarball, so you can get a better idea of how it all fits together. So off you go, go and create a plug-in yourself!

This article provided by sitepoint.com.


6 things to try in Rails this year

Wednesday, January 9th, 2008

It seems that blog posts in the first couple of weeks of the new year (happy new year by the way) follow the “x things to do this year” meme as a virtual homage to new years resolutions. Never one to buck a trend, I have prepared this short list of things you should try in Ruby and in Rails - I hope to cover each topic in more detail over the next couple of weeks.

  1. Install Rails: This is aimed at those of you out there that haven’t tried Ruby on Rails yet. Jump in - have a go, there are plenty of resources out there, and it is fairly easy to install regardless of your platform
  2. Upgrade to Rails 2.0: I have covered what’s new in Rails 2.0 in a number of my previous posts, and upgrading isn’t really THAT difficult if you follow the steps and fix any deprecation notices.
  3. Write a plugin: Plugins allow you to re-use common patterns without having to resort to the dreaded cut-and-paste keys. Rails has a built in plugin generator that gives you the skeleton code, all you need to do is to mix-in the right modules - oh, and write the code…
  4. Try out RESTful routes: RESTful Rails have been around for a while now, but many of the tutorials around the net are still CRUD based, so if you are a Rails beginner, you might not have tried them out yet.
  5. Use Ruby as your scripting language: Because Rails does such an excellent job of doing the hard work, it is very likely that you have never had to manually connect to a database or read the contents of a directory or performed other mundane tasks in Ruby. If you have to do any scripting, instead of PERL or Python, use Ruby - it will help you better understand the nuances of the language.
  6. Refactor your code the Ruby way: If you have come from other C-like languages (such as PHP or Java) you would
    be used to the idioms from that style of coding. Try refactoring your code to use blocks instead of for loops, or using inline if statements - you can squeeze a lot into one line in Ruby, see how far you can push it. Again, this is a great exercise to learn the language.

Go on, try them out - the new year is a great time to try something new!

This article provided by sitepoint.com.


Flexible Fixtures in Rails 2

Wednesday, December 12th, 2007

As Matt Magain pointed out yesterday, Rails 2.0 is now gold! Not a lot has changed feature wise from the PR (makes sense - features were frozen at that point), although it seems that the new improvements to fixtures managed to slip in to the final version.

Rather than having to map foreign keys in your fixtures using id numbers, you can use fixture names, which makes life a whole lot easier. So you can now write:

users.yml

joe_blogs:
  id: 1
  first_name: Joe
  last_name: Blogs
mary_smith:
  id: 2
  first_name: Mary
  last_name: Smith


websites.yml

website_1
  id: 1
  user: joe_blogs
  url: "http://www.joeblogs.com"

website_2
  id: 2
  user: mary_smith
  url: "http://mary.smith.id.au"

which obviously makes a lot more sense to a human reading it, especially when you have a large number of fixtures across many models.

Let me join Matt in congratulating the Rails core dev team for achieving this milestone - roll on Rails 3!

This article provided by sitepoint.com.


Processing HTML with Hpricot

Wednesday, November 21st, 2007

In this world of Web2.0 mashups and easy API access, it is quite refreshing how easy it is to pull data for third party sites and re-mash it into something new. Unfortunately, not everyone has been bitten by this bug, so we as developers sometimes have to do a little more leg work to get the information we need. A common technique is called a screen scrape where your application acts like a browser and parses the HTML returned from the third party server.

Although this should be simple enough, anyone who has ever tried to do this knows the pain of dancing with regular expressions in an attempt to find the the tags that you need. Luckily, us rubyists have the Hpricot library which takes the hard work out of parsing HTML. Hpricot allows developers to access html elements via CSS-selectors and X-Path, so you can target specific tags really easily. And because it is written in C, it is pretty fast too.

Installation

Hpricot is a gem, so installation is as easy as:

gem install hpricot

The just require the library at the top of the ruby file:


require 'hpricot'

Usage

Lets take this HTML snippet:


<html>
  <head>
    <title>Snippet</title>
  </head>
  <body>
    <div id="container">
      <div id="navigation">
        <ul>
          <li><a href="/">Home</a></li>
          <li><a href="/contact></a></li>
        </ul>
       </div>
       <div id="sub-content">
          <p>This would be some sort of sidebar</p>
       </div>
       <div id="content">
         <p>This is paragraph 1</p>
         <p>This is paragraph 2</p>
       </div>
     </div>
   </body>
</html>

We can easily pull out the content of the paragraphs by doing this (Let’s assume the HTML is already stored in the variable @html)


doc = Hpricot(@html)

pars = Array.new
doc.search("div[@id=content]/p").each do |p|
  pars << p.inner_html
end

Yep - that’s it. You now have an array with two elements that are the same as the copy in the two p tags. Notice that the p tag in the sub-content div isn’t pulled in?

It doesn’t end there though, you can also manipulate the HTML - which can come in handy if you wanted to, say, create a quick and dirty mobile version. Let’s say we wanted to remove the sub-content div from the mobile version, we could do this:


doc = Hpricot(@html)

doc.search("div[@id=sub-content]").remove

puts doc

The resultant HTML no longer has a div called sub-content!

To add a new class to the navigation ul is as simple as:


doc = Hpricot(@html)

doc.search("div[@id=navigation]/ul").set("class", "nav")

This is just the tip of the iceberg - the library is really powerful and simple to use. Go and check out the official page for more (less trivial) examples.

Disclaimer: You should make sure you have permission for the website owner before screen-scraping their site.

Preparing for Rails 2.0: Controller-based exception handling

Wednesday, November 7th, 2007

Since Ruby is a pure Object-Oriented Language, exceptions play a big role in the flow of control. Previously, you had the choice of rescuing exceptions at a local level or you could override the rescue_action method in your controller.

The former method gave you really fine-grained control of what to do in the case of an exception:


begin
    user.save!
rescue ActiveRecord::RecordInvalid
    render :action => 'new'
end

In this case, if the ActiveRecord::RecordInvalid exception is raised (the save! method will raise this if validation fails) Rails will render the ‘new’ action. It became clear, though that adding begin/rescues around the same methods is pretty time consuming and not very DRY - which is where the rescue_action became helpful:


def rescue_action(exception)
  if exception == ActionView::TemplateError
    render :template => 'errors/404'
  else
    super
  end
end

This (rather contrived) example will trap any ActionView::TemplateError and render the 404.erb file in the /app/views/errors directory. You are able to drop that method into any controller (including app_controller), but again, there is a lot of work involved in setting them up, making sure each controller performs the correct action for a given exception, which is why Rails 2.0 introduces rescue_from.

rescue_from is an attribute of each controller, and allows you to define a method to run when a particular exception is called. So the above example would become:


rescue_from ActionView::TemplateError, :with => :render_404

def render_404(exception)
   render :template => 'errors/404'
end


or if you prefer to use a inline block:


rescue_from ActionView::TemplateError do { render :template => 'errors/404' }

In the current PR release, the rescue_from technique can only catch exceptions of an exact type, so it wouldn’t catch sub-classed exceptions - if you had a custom exception called MyTemplateError that extends ActionView::TemplateError the above code won’t work. The good news is a patch to edge rails fixes this issue, so the release version of Rails 2.0 will work as expected.

This article provided by sitepoint.com.


Preparing for Rails 2.0

Wednesday, October 31st, 2007

Anyone that has used Rails 1.2.3, 1.2.4 or 1.2.5 may have noticed a number of deprecation notices in their development logs. Whilst these deprecated methods still work as expected in 1.2.x versions, you will come-a-cropper when you try to upgrade to Rails 2.0. So what do you need to do and what tools are out there to help you with the move? Glad you asked.

The first thing you can do it run your code through a code checker — Geoffrey Grosenbach has released a great rake task which digs through your code looking for the old methods. It will give you hints of how to fix the issues, but lets look at them a little more closely.

@params, @session, @flash, @env

As of Rails 2.0, you won’t be able to directly access the above instance variables. They have been replaced with methods, which makes customising their actions much easier. It also allows the internals of Rails to change without breaking the API. This is very easy to fix - just remove the @ in front of those variables - they will work exactly the same.

find_all, find_first, render_partial

In earlier version of Rails there were a number of grouped methods, that do very similar things - find, find_all and find_first all fetch records from the database, the only difference is the number of records they return. It was decided to combine these methods in to one where they are differentiated by passed in options. So find_all becomes find(:all) and find_first becomes find(:first) and render_partial becomes render(:partial).

Forms

Out of all the HTML helpers, the form tag was an anomaly because it required a start AND end helper. To make it fit in with way the rest of Rails works and to facilitate dynamic form generation, a block method called form_tag was created. This particular update has a trap in it through - because blocks don’t return values, the ERB tag you use must not have an = sign, so


   <%= start_form_tag %>
       <!-- Form stuff -->
   <%= end_form_tag %>

becomes


    <% form_tag do %>
        <!-- Form stuff -->
    <% end %>

Notice the omission of the equals sign in the latter example?

Also note that passing :post => %gt; true is deprecated. With the push for RESTfulness, the form needs to know about the other HTTP verbs, put and delete, so a new option has been created:


    <% form_tag :method => :post do %>
        <!-- Form stuff -->
    <% end %>

Plugins

A number of what used to be core components of rails have been moved out into plug-ins so as not to clutter the core with stuff that you don’t use very often. It also means that the development of the plugins can be much quicker than that of the core. Probably the major extraction is the third-party database interfaces. Now, by default only MySQL, SQLite and PostgreSQL are supported out of the box. All other databases are supported via gems named activerecord-database-adapter. If you want to use an Oracle just run

gem activerecord-oracle-adapter

and you will be peachy again.

Other extractions of note are the acts_as plug-ins. If you use acts_as_tree or acts_as_list in your model, you will need to script/plugin install them and the built-in pagination has now become the classic_pagination plug-in. Note that by the developers own admission that plug-in is slow (and was slow when it was in core), so if you use it, you may want to think about migrating across to the new and improved will_paginate plug-in.

So hop to it and get your web apps upgraded now before the rush!

This article provided by sitepoint.com.


Rails 2.0 features: Multiple views

Friday, October 26th, 2007

The seed has been sewn for the next major release of the Ruby on Rails framework. Towards the end of last month, the Preview Release was announced and now that I have had a chance to play with it, I thought it timely to outline some of the new features.

Multiple Views

In version 1.2 of Rails, the respond_to block was introduced, which made serving up differerent data types, like XML or JSON really easy. All you needed to do was something like this:


def index
    @stories = Story.find :all
    respond to { |format|
        format.html {}
        format.xml {
            render :xml => @stories.to_xml
        }
        format.json {
            render :json => @stories.to_json
        }
    }
end

Then, on the web browser, if you appended the file extension (eg /stories/index.xml) and you would get the content delivered in the requested format. You could even create your own custom types by adding MIME::Type.register to the bottom of your environment.rb file.

One of the problems with this approach though, was there was no way to serve up different HTML pages based on the file extension. Because of the way the MIME::Type parser worked, adding another content handler with a mime type of text/html clobbered the default handler which meant the above code would serve up the wrong view.

Enter Mime::Type.register_alias

Now you can tell Rails to respond with HTML to as many file types as you like! Say you are designing a mobile version and an iPhone version of your site, you can create two new formats by dropping the following code in to the new /config/initializers/mime_types.rb file:


Mime::Type.register_alias "text/html", :iphone
Mime::Type.register_alias "text/html", :mobile

This makes the following possible:


def index
    @stories = Story.find :all
    respond to { |format|
        format.html {}
        format.xml {
            render :xml => @stories.to_xml
        }
        format.json {
            render :json => @stories.to_json
        }
        format.iphone {
           // Serve up the iPhone version
        }
        format.mobile {
           // Serve up the mobile version
        }
    }
end

Of course, having to manually render a different version in every respond_to block isn’t very DRY, so a new naming convention has been created for all of the view files. Rather than calling the view file in the example above index.rhtml, you can create three different versions based on the format that you are serving up, eg: index.html.erb, index.iphone.erb and index.mobile.erb.

If rails finds a matching view it will serve that up, if not it will serve up the default .html.erb or .rhtml file. This makes serving up different versions of your site even easier.

This article provided by sitepoint.com.


 

hedges