Merb - First steps

Posted by Nucc

I’ve read a lot of Merb, so I decided to try it. First it seems to be very poor framework, and it’s true. It’s only a skeleton unlike rails. First I tried

script/generate model User name:string email:string

and I got a pure User class without Datamapper, ActiveRecord, or other ORM. After googling I found the solution, it need to set use_orm :datamapper in dependencies.rb. For datamapper install use this:

sudo gem install datamapper
sudo gem install merb_datamapper
sudo gem install do_mysql

It’s okay, we generate again our model file.

script/generate model User name:string email:string

The result:

  1. class User < DataMapper::Base
  2.   property :name, :string
  3.   property :email, :string
  4. end

Okay, it’s nice, but how can we migrate with the database? We have a config/database.sample.yml file like in rails, edit this. It’s very nice, in Rails we have to set username, pass, database for all environment, here we can use inheritance.

:development:
  &defaults
  :adapter: mysql
  :database: merb_test
  :username: root
  :password:
  :host: localhost

:test:
  <<: *defaults
  #:database: sample_test:

production:
  <<: *defaults
  #:database: sample_production

Okay, it’s nice, try to migrate. … I’ve need some time, to solve this very simple problem. In rails, we have rake db:migrate, but in merb it’s not, or not ready yet. Okay, no problem, I found this solution:

In config/merb_init.rb insert this:

  1. DataMapper::Persistence.auto_migrate!

It will migrating our models with database before merb server start. Let’s look an example. If we want to add a column to our User table, we only need to set another property tag, like:

  1. class User < DataMapper::Base
  2.   property :name, :string
  3.   property :email, :string
  4.   property :message, :string
  5. end

After a restart Users table looks:

desc users;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | int(11)     | NO   | PRI | NULL    | auto_increment |
| name    | varchar(50) | YES  |     | NULL    |                |
| email   | varchar(50) | YES  |     | NULL    |                |
| message | varchar(50) | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+

Nice. But! I’ve some problems. How can we manage, when new columns have an initialize value? How can we rename row? It’s very good for smaller projects, but what we can do, if we have an already exists database with a lot of data? It’s not trivial for me?

I shouldn’t remove migrating, but change it. I forget the numbers before the migration name, and use creation date for order them. Every migration file should has a creation date, and migration script use it for order them. It’s only an idea.

Another problem in Merb, controllers don’t get Controller suffix in class name. It seems to comfortable, but what happens, if we have a User model, and we want to use an User controller to manage our model. It’s problem. Need to use different namespaces for models and controllers, or use suffix or prefix in controllers like rails.


Erubis

Posted by Nucc

I’ve been looking for memcache solutions, when I found merb. Merb is similar to Rails, it’s developed by Ezra Zygmuntowicz (author of Deploying Rails). Merb uses Erubis instead of ERB. Erubis is refinement of ERuby, three times faster than ERB, it has auto HTML escaping support, but the most important for me is the preprocessing ability.

I tried to install Erubis to Rails 2.0.2 for testing, but I had problems. I would like to share how to setup in Rails 2.0.2, because it’s not the same in 2.0.1 and 2.0.2

First, setup from gem

sudo gem install erubis --include-dependencies

We create /config/initializers/erubis.rb for loading on boot.

  1.  
  2. class ActionView::Base
  3.   private
  4.     def convert_template_into_ruby_code
  5.       # dummy
  6.     end
  7.  
  8.     def delegate_compile_with_preprocessing(handler, template)
  9.  
  10.       if ::Erubis::Helpers::RailsHelper.preprocessing
  11.         preprocessor = ::Erubis::Helpers::RailsHelper::PreprocessingEruby.new(template)
  12.         template = self.instance_eval(preprocessor.src)
  13.         if ::Erubis::Helpers::RailsHelper.show_src
  14.           logger.debug "** Erubis: preprocessed==<<’END’\n#{template}END\n"
  15.         end
  16.       end
  17.  
  18.       delegate_compile_without_preprocessing(handler, template)
  19.     end
  20.  
  21.     alias_method_chain :delegate_compile, :preprocessing
  22. end
  23.  
  24. require ‘erubis’
  25. require ‘erubis/helpers/rails_helper’
  26.  
  27. module ActionView
  28.   module TemplateHandlers
  29.     class Erubis < TemplateHandler
  30.  
  31.       def compile(template)
  32.         klass = ::Erubis::Helpers::RailsHelper.engine_class
  33.         properties = ::Erubis::Helpers::RailsHelper.init_properties
  34.         klass.new(template, properties).src
  35.       end
  36.     end
  37.   end
  38. end
  39.  
  40. ActionView::Base.register_default_template_handler :erb, ActionView::TemplateHandlers::Erubis
  41. ActionView::Base.register_template_handler :rhtml, ActionView::TemplateHandlers::Erubis
  42.  
  43. # settings
  44. Erubis::Helpers::RailsHelper.engine_class = Erubis::FastEruby
  45. Erubis::Helpers::RailsHelper.show_src = true
  46. Erubis::Helpers::RailsHelper.preprocessing = true

In settings, we have three options. I use FastEruby, and I turned on show_src to see precompiled html code in console. If you want to use preprocessing, need to set preprocessing true. Preprocessing is useful for loop, but the syntax changes, when you use it. Instead of <% %> you have to use [% %], and if you have variable, you have to use _?(’variable’). I tried to test in a view,

  1. <% 1.upto 1000 do %><%= link_to "My post", _?(’@post link’) %>

with ERB it’s generate 49-61 req/sec, erbius without preprocessing is 51-74 req/sec, and with preprocessor 90-120 req/sec. If I have more time, I try to make test cases, and publish them.

One comment: If you use html escaping function, change every <%= %> tags to <%== %> ;) I’ve need some time to realize my mistake.


Slots plugin

Posted by Nucc

I’d like to share my last Rails plugin which add comfortable management for remote_calls. I have a work for developing a photo manager. It needs a lot of remote call for change for example the name of the album, upload photo, remove uploaded photos from the div tree, rotate image without reload the whole page. The currently solution in rails like this:

/app/view/photo/index.rhtml

  1. <div id="photo_1"></div>
  2. <div id="photo_2"></div>
  3. <%= link_to_remote "Rotate Photo 1",
  4.         :url => {:action => "rotate", :id => "1"} %>

/app/controllers/photo_controller.rb:

  1. class PhotoController < ApplicationController
  2.   def index
  3.   end
  4.  
  5.   def rotate
  6.     @photo = Photo.find_by_id(params[:id])
  7.     @photo.rotate(90)
  8.     @photo.save!
  9.     render :update do |page|
  10.       page["photo_1"].replace_html  :partial => "photo",
  11.                                     :object => @photo
  12.     end
  13.   rescue
  14.   end
  15. end

If we have a lot of link_to_remote for different methods, we have to write render :update .. for each one. The other problem, what happens if one of my action try to call another action. For example, always when I rotate an image, I’d like to share with the user what happens (flash a div element, with “Photo rotated” message). If I write another method for flashing message, it would be double rendering. If I write a helper method, I should always pass the page parameter, and if the message use my params[], I should pass it too. I have a solution for this problem.

Install this plugin in your Rails framework.

script/plugin install https://svn.bteam.hu/plugins/slots/trunk/

Let’s look the changes

/app/view/photo/index.rhtml

  1. <div id="message"></div>
  2. <div id="photo_1"></div>
  3. <div id="photo_2"></div>
  4. <%= link_to_remote "Rotate Photo 1",
  5.         :url => {:action => "rotate", :id => "1"} %>

/app/controllers/photo_controller.rb:

  1. class PhotoController < ApplicationController
  2.   slots :rotate, :message
  3.  
  4.   def index
  5.   end
  6.  
  7. end

/app/helpers/photo_helper.rb

  1. class PhotoHelper
  2.   def rotate
  3.     @photo = Photo.find_by_id(params[:id])
  4.     @photo.rotate(90)
  5.     @photo.save!
  6.  
  7.     page["photo_1"].replace_html  :partial => "photo",
  8.                                   :object => @photo
  9.     message("Photo was rotated by 90 degree")
  10.     #Or we can use
  11.     # message("Photo #{params[:id]} was rotated by 90 degree")
  12.   rescue
  13.   end
  14.  
  15.   def message(msg)
  16.     page["message"].replace_html  :partial => "message",
  17.                                   :object => msg
  18.   end
  19. end

As you see, I put our remote called methods into helper. It’s necessary because only helpers can change our views. If we want to use the params hash in the message method, we can do this.

In controllers, when we call slots method, it generates a method with the same name as the slot, so we can use before_filter for this methods.

Enjoy it!