Speaker at RailsConf Europe 2008 3

Posted by luca
on Wednesday, June 18

I'm proud to announce my presence as speaker at the RailsConf Europe 2008 with a speech on Click to Globalize.

Rails: Single File App 0

Posted by luca
on Tuesday, June 03

I took inspiration from the Pratik Naik post, and realized a more simplistic version of its Rails single file app. My implementation has only Rails as unique dependency.

require 'rubygems'
require 'action_controller'
require 'webrick'
require 'webrick_server'

class HelloWorldController < ActionController::Base
  session :off
  def index; render :text => 'Hello World!' end
end

ActionController::Routing::Routes.draw do |map|
  map.root :controller => "hello_world"
end

DispatchServlet.dispatch :port => 3000,
    :server_root  => File.dirname(__FILE__)

Update 2008-06-04: I just wrote another version which also uses ActiveRecord and a template.

require 'rubygems'
require 'activerecord'
require 'action_controller'
require 'webrick'
require 'webrick_server'

ActiveRecord::Base.establish_connection(
  :adapter  => 'sqlite3',
  :database => 'tiny_rails.sqlite3',
  :timeout  => 5000)

ActiveRecord::Schema.define do
  create_table :people, :force => true do |t|
    t.string :first_name
  end
end
class Person < ActiveRecord::Base; end
Person.create :first_name => 'Luca'

File.open('index.html.erb', 'w') do |f|
  f << "Hello, my name is <%=h @person.first_name %>!\n"
end

class HelloWorldController < ActionController::Base
  session :off
  def index
    @person = Person.find :first
    render :file => 'index.html.erb'
  end
end

ActionController::Routing::Routes.draw do |map|
  map.root :controller => "hello_world"
end

DispatchServlet.dispatch :port => 3000,
    :server_root  => File.dirname(__FILE__)

Just start the script and point your browser at http://localhost:3000!

Acts As Resource: Rails 2.1 ready and moved to GitHub 0

Posted by luca
on Wednesday, May 14

Acts As Resource is ready for the imminent Rails 2.1!

I also moved it to GitHub, the new repo is http://github.com/jodosha/acts-as-resource/tree/master, the SVN one is deprecated.

If you enjoyed this post, feel free to recommend me on Working With Rails.

Click to Globalize: rewritten and moved to GitHub 4

Posted by luca
on Monday, May 12

Click to Globalize has been rewritten, in order to use all instance methods of the JavaScript class, instead of class methods.

I also fixed some tiny issues:

  • The form_authentication_token method is called only if the application is protected against the CSRF attacks (protect_against_forgery? returns true)
  • It uses as parameter key what request_forgery_protection_token returns, instead of the hard-coded authenticity_token
  • The JavaScript class uses Prototype's dom:loaded custom event.

I also migrated the plugin GitHub. The new repo is http://github.com/jodosha/click-to-globalize/tree/master, so the oldest one is deprecated.
Have a nice globalization!

If you enjoyed this post, feel free to recommend me on Working With Rails.

Ruby on Rails: Test Model Domain Changes 0

Posted by luca
on Monday, April 28
You know how tests are fundamental for a well-developed project, for this reason we should create step-by-step a net of test cases. Of course we also should be able to change rapidly our tests as the same we do with our code. Ruby on Rails is a great framework, because its shortcuts, the wide usage of DSL etc.. All this stuff can save a lot of time, but what about tests? Are we really able to follow our code?

Create and Destroy

ActiveSupport provides few useful tools to improve our test, I really appreciate assert_difference and assert_no_difference. Basically, this two methods accepts as arguments a code chunk (as string) and a block. When the test run, it binds the block first, then it assert if the changements caused by the block call are the same expected by first argument.
def test_should_be_created
  assert_difference 'Person.count' do
    create_person
  end
end
We are testing a Person creation, we pass as first argument 'Person.count', and the code that should correctly save the person. If the model will be saved, a new record should exists into the database table. At this moment assert_difference evaluates the first argument, and assert if there are differences in the Person count.
def test_should_be_destroyed
  assert_difference 'Person.count', -1 do
    destroy_person
  end
end
This example is just a bit different, we are also passing a Fixnum as argument. This because we want assert another difference from the default one, which is +1. So, if the model will be correctly saved, we will have a negative difference, of one, into the Person count.
def test_should_require_first_name_on_create
  assert_no_difference 'Person.count' do
    create_person
    assert person.errors.on(:first_name)
  end
end
The third example uses assert_no_difference, to test aganist model validations. ActiveRecord, by default, prevents the creation of a model if a validation doesn't pass. In this case our model requires first_name as mandatory attribute, but unfortunately it's nil, so the creation fails and the brand new record will be not created.

Update

As you can see, those two methods are very useful for test creation and destruction of models, but totally missing the goal of the update. In fact, the update process of a record, doesn't produces numerical differences. I created two methods to supply this lack.
def assert_updated(model, message = nil, &block) 
  yield
  assert_not_equal model.attributes, model.reload.attributes, message
end
def assert_not_updated(model, message = nil, &block)
  yield
  assert_equal model.attributes, model.reload.attributes, message
end
Just add them to your test/test_helper.rb, and they will be available in all your test cases.
def test_should_update
  assert_updated person do
    update_person
  end
end
First, you should notice that the first argument it isn't a string but an ActiveRecord. The behaviour of this method is similar to the previous I illustrated, it first bind the block, then assert if the attributes of the model are different. It internally uses ActiveRecord::Base#attributes which returns an hash of model attributes, then assert the differences with Ruby's assert_not_equal.
def test_should_require_first_name_on_update
  assert_not_updated person do
    update_person
    assert person.errors.on(:first_name)
  end
end
Similarly to all other examples, it first performs the block, call then assert there are no changes in the model attributes.

Conclusion

Those methods should provide a rapid way to write and mantain your test cases. If you enjoyed this post, feel free to recommend me on Working With Rails.

Click To Globalize 0

Posted by luca
on Saturday, January 26

Click To Globalize

Click To Globalize is an extension for Globalize plugin, it allows to edit in place globalized labels. With this plugin you don't have to create a globalization back-end, but just edit your interface in place!!

If you have a previous globalization experience, you probably noticed that the main problem of dedicated back-ends is the lack of the context where the string will be placed in. It isn't a trivial issue: you'll never know if the meaning of your string is harmonious with other labels and how your string will be rendered, until the page load.

Now you can forget this issues, you can directly globalize in place!!

Getting Started

  1. Install Globalize, if you don't already done.
  2. Install Click To Globalize:
    $ ./scripts/plugin install git://github.com/jodosha/click-to-globalize.git
  3. Run the setup task:
    $ rake click:setup
  4. Add at the end of your layout the following code:
    <%= click_to_globalize -%>
  5. Put in your view:
    <%= 'hello_world'.t %>
  6. Start the server and click to globalize.

Prerequisites

  • Globalize plugin: www.globalize-rails.org.
  • Prototype >= 1.5.1.1, this version is provided by Click To Globalize installation.
  • RedCloth gem (optional) for textile formatting.
  • BlueCloth gem (optional) for markdown formatting.

Install

  1. Install Globalize, if you don't already done.
  2. Install Click To Globalize:
    Rails 2.1.x
    $ ./script/plugin install git://github.com/jodosha/click-to-globalize.git
    Rails 2.0.x
    $ ./script/plugin install http://dev.23labs.net/svn/rails/plugins/click_to_globalize/trunk
    Rails 1.2.x
    $ ./script/plugin install http://dev.23labs.net/svn/rails/plugins/click_to_globalize/branches/for-1.2.x
  3. Run the setup task:
    $ rake click:setup
  4. Run the tests (optional):
    $ rake click:test
  5. Choose your languages, they will be used to create a picker menu.
    class ApplicationController < ActionController::Base
      self.languages = { :english => 'en-US', :italian => 'it-IT' }
    end
  6. If you like to use wiki-formatting styles, you could use textile (RedCloth) or markdown (BlueCloth).
    class ApplicationController < ActionController::Base
      self.formatting :textile
    end
  7. Personalize the access to the globalization features, overriding #globalize:
    class ApplicationController < ActionController::Base
      def self.globalize?
        current_user.admin?
      end
    end

    NOTICE: #globalize? is method to turn on/off all the Click To Globalize features.
  8. Add at the end of your layout the following code:
    <%= click_to_globalize -%>

Uninstall

$ ./script/plugin remove click_to_globalize

Features

  • In-place editing for each globalized string.
  • Easy and painless plug-in/plug-out process.
  • Unobtrusive Javascript.
  • Auto transformation from input text to textarea for long strings.

Common Issues

  • The install process upgrades your Prototype version to 1.5.1.1 only if needed, but it's advisable to backup your scripts.
  • Since the Globalize plugin creates folders like for-1.2, be sure to rename the folder to globalize.
  • Due to unobtrusive nature of the plugin, each page is parsed by javascript to find the right element and bind to it an Ajax.InPlaceEditor.
    Be sure your (X)HTML is wellformed.
    NOTICE: If you use the Rails 1.2.3 scaffold system, Click To Globalize doesn't works. Cleanup the code before to use.
  • If you use a wiki-formatting style it could be advisable to use #h to avoid security problems (i.e. XSS).
    <%= textilize(h('some_text'.t)) %>

Contribute

  • Check out the code and test it:
    $ git clone git://github.com/jodosha/click-to-globalize.git
    $ rake click
  • Create tickets at the project Trac.
  • Create a patches and add as attachement to the tickets.

Repository

http://github.com/jodosha/click-to-globalize/tree/master

Credits

Javascript tests are based on Prototype test libs.

Vote

If you find it useful feel free to add to your favs on agilewebdevelopment.com.

Copyright

Copyright © 2007 - 2008 Luca Guidi - 23 Labs, released under the MIT license.

Tutorials

  • Getting Started --high resolution
    Click To Globalize: Getting Started [High Resolution]
  • Getting Started
  • Restrict The Access
  • Text Area Transformation
  • Formatting
  • How to Prevent XSS

Click To Globalize: High Resolution Video Tutorial 3

Posted by luca
on Saturday, January 26

Click To Globalize: Getting Started [High Resolution]

The video tutorial for Click to Globalize is now available in high resolution: Click To Globalize: Getting Started.

Rails: How To Create Custom Validations 0

Posted by luca
on Friday, December 21

Often our model objects leaning toward to be confused or noisy, due to validations DSLs. Imagine a class Answer, with an attribute, that should be exactly a string representation of a boolean. Ok, I know it's an odd example, but: it's trivial enough to make this example clear, and.. It happened to me to deal with this situation. :-P

class Answer < ActiveRecord::Base
  validates_inclusion_of :value, :in => %w( true false ),
                         :message => "Should be exactly true or false."
end

Now, we try to clean-up a bit this code.
First, create a file named validations.rb into lib, then copy and paste this code:

module ActiveRecord
  module Validations
    module ClassMethods
      @@boolean_values = %w( true false )
      @@validates_boolean_msg = "Should be exactly #{@@boolean_values.join(' or ')}."

      # Check if the value is a boolean: <tt>true</tt> or <tt>false</tt>.
      def validates_boolean(*attr_names)
        configuration = { :message   => @@validates_boolean_msg,
                          :in        => @@boolean_values }

       configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
       validates_inclusion_of attr_names, configuration
      end
    end
  end
end

Then we are going to add the following line at the end of environment.rb
require 'validations'

Let's clean the code:

class Answer < ActiveRecord::Base
  validates_boolean :value
end

Is it better? Maybe.. ;-)

Click To Globalize: Rails 2.0 Ready 6

Posted by luca
on Friday, December 14

I have finished to work on Click To Globalize, to made it Rails 2.0 compatible.

What's Changed?

All and nothing: from the user point of view, the plugin has the same behaviors of the previous version. My recent activity was a refactoring, now it:

  • Works with CSRF Killer
  • Works with Prototype 1.6.0.1 and Scriptaculous 1.8.0.1
  • Works with rewritten version of Scriptaculous Ajax.InPlaceEditor
  • Works with new Prototype events handling
  • Uses new Prototype's Element#addMethods and Function#wrap to add methods and AOP
  • Uses Protoype Hash#get, instead of square brackets
  • Uses .html.erb as helper, instead of .rhtml
  • Has a more clean installation/disinstallation process
  • Has DRYed up tests
  • Hasn't prototype.js into the packaging

How To Use It?

Rails 2.0

$ ./script/plugin install http://dev.23labs.net/svn/rails/plugins/click_to_globalize/trunk

Rails 1.2.x
$ ./script/plugin install http://dev.23labs.net/svn/rails/plugins/click_to_globalize/branches/for-1.2.x

For a detailed guide, howtos, snippets, video-tutorials and other infos, please visit the Click To Globalize page.

Click To Globalize: Repository Changes 2

Posted by luca
on Sunday, December 09

As I previously announced, I'm working on Rails 2.0 compatibility for Click To Globalize.

I decided to move the stuff for Rails 1.2.x to for-1.2.x branch and continue the porting into trunk.

How To Install

Rails 2.0

$ ./script/plugin install http://dev.23labs.net/svn/rails/plugins/click_to_globalize/trunk

Rails 1.2.x
$ ./script/plugin install http://dev.23labs.net/svn/rails/plugins/click_to_globalize/branches/for-1.2.x

Click To Globalize: Working On Rails 2.0 Compatibility 1

Posted by luca
on Sunday, December 09

As you already know, Rails 2.0 it's shipped with updated version of Prototype and Scriptaculous.

Prototype team has committed some breaking changes (e.g. Hash class), and Scriptaculous now has a brand new, rewritten InPlaceEditon.

Those elements are fundamental for Click To Globalize and I'm working on new version for Rails 2.0.

Be patient, I'll soon release it.

Acts As Resource: Rails 2.0 Ready 0

Posted by luca
on Sunday, December 09

Acts As Resource is ready for Rails 2.0!!

This plugin combines both ActiveRecord and ActiveResource features in one class. It easily allows to deal with a remote REST service or with a local database.

If you want read more visit the plugin page or install with:

$ ./script/plugin install http://dev.23labs.net/svn/rails/plugins/acts_as_resource

Ruby on Rails 2.0: Released 0

Posted by luca
on Saturday, December 08

As I previously announced Ruby on Rails 2.0 was released.

What's new?

Active Record

  • Performances
  • Sexy Migrations
  • Foxy Fixtures
  • XML Deserialization
  • JSON Serialization
  • acts_as Plugins Removal From Core
  • Database Adapters Gems
  • with_scope Protection

Action Pack

  • Resources
  • REST Improvements
  • Multiview
  • Record Identification
  • HTTP Loving
  • Security Improvements
  • Exception Handling
  • Cookie Store Sessions
  • New Request Profiler
  • AtomFeedHelper

Active Resource

  • Official Inclusion In Core
  • Remote CRUD

Action Mailer

  • Bug Fixes
  • Testing Improvements

Active Support

  • Date Extensions
  • Array#rand
  • Hash#except
  • Testing Improvements

..And More

If you want more details read the official announcement or check the Rails APIs.

Ruby on Rails 2.0 Will Be Soon Released 0

Posted by luca
on Thursday, December 06

Ruby on Rails 2.0 will be released in the next hours!!

Acts As Resource: Combining ActiveRecord and ActiveResource 0

Posted by luca
on Wednesday, November 28

Would you use both ActiveRecord and ActiveResource in one class?
Now with Acts As Resource you can!!

Example

class Carrot
    acts_as_resource
    self.site = 'http://localhost:3000'

    belongs_to :bunny

    validates_presence_of :color
    validates_uniqueness_of :color
    validates_length_of :color, :within => 2..23,
                        :if => lambda { |c| c.color && !c.color.empty? }
    validates_format_of :color,
                        :with => /[\w\s]+$/,
                        :if => lambda { |c| c.color && !c.color.empty? }

    before_create :please_call_me_before_create
    def self.validate
      logger.debug("VALIDATE #{color}")
    end

    def please_call_me_before_create
      logger.debug("Ohhh, so you called me..")
    end  
  end

About

You can find many informations about Acts As Resource on related page on my blog.

Vote

If you find it useful feel free to add to your favs on agilewebdevelopment.com