Ruby on Rails has changed a lot these few years. There are some security issues found recently. One of them is regarding the vulnerability in the JSON parser that comes with Active Support. You can read more here. However, the patch provided is only available for Rails 2.3.x and 3.0.x. I checked the code for Rails 2.2.2 and found that this version is affected as well. Without the official patch, I have to come up with my own patch for that. This is a serious problem if your application is not up to date with Rails. I developed a Ruby on Rails website that provides stocks information about three years ago with a small team, which stayed with Rails 2.2.2. Now it is time to upgrade it to the latest Rails 3.2.12. Below is how I did it and some of the major changes that has to be made in the code.

 

The whole project structure has changed quite a lot between Rails 2 and Rails 3 especially with the introduction of asset pipeline and bundlers. The easier way to upgrade your apps is to create a blank new Rails 3 apps and move in all the new folders into your old Rails 2 apps. For the files with the same names under same directories e.g. config/environments.rb, config/environments/production.rb, there are some API/format changes, so you need to compare the contents and see how to merge them. After you have done that, you can try to start your rails applications, which I believe the server can’t even be started. You should check every single error messages shows up in the console and fix them one by one until everything is fine. Below are some major changes that I met with.

 

  1. For the app/controllers/application.rb, it should be named as application_controller.rb now. Otherwise ‘uninitialized constant ApplicationController’ would be thrown.
  2. ENV['RAILS_ENV'] is now deprecated, use Rails.env instead.
  3. Rails.root class used to be String. Now it is changed to PathName. So you can’t do things like below:
    File.read(Rails.root + "/config/streaming_config.yml")
  4. lib folders are not auto loaded. So you will see some missing constant errors. To auto load the lib folders add below two lines to the config/application.rb.
    config.autoload_paths += %W(#{config.root}/lib)
    config.autoload_paths += Dir["#{config.root}/lib/**/"]
  5. filter_parameter_logging is no longer available. To filter out the parameters you can do it in the config/application.rb.
    config.filter_parameters += [:password]
  6. You cannot access controller methods in the view with @controller anymore. You have to use controller instead.
  7. For action view rendering, you no longer need to call h(string) to escape HTML output, it is on by default in all view templates. In Rails 2 you need to do below to escape the parameters, if not, you are vulnerable for XSS attacks.
    <%= h @params[:user_name] %>

    In Rails 3, this html escape is on by default. However if the variable or contents you are trying to render contains html, and you want to render the html you have to explicitly call raw methods or html_safe method.

    <%= raw @page.content %>
    <%= @page.content.html_safe %>

    I forget to put raw or html_safe in some of the views, and it renders escaped html instead. So you may want to check across the whole site to make sure everything is alright.

  8. For form_tag and form_for, you need to use <%= %> instead of <% %>, otherwise the form won’t be rendered at all.
  9. will_paginate 2 won’t work with Rails 3. Have to upgrade to will_paginate 3 otherwise uninitialized constant ActiveRecord::Associations::AssociationCollection error will be thrown.
  10. Array.paginate will throw error.The Array#paginate method still exists, too, but is not loaded by default. If you need to paginate static arrays, first require it in your code: require ‘will_paginate/array’
  11. For active record, save(false) changed to
    save(:validate => false)
  12. request.request_uri changed to request.url
  13. REXML::Document is not auto loaded, need to explicitly require it before using.
    require 'rexml/document'
  14. rake API changes. The :needs => :environments is deprecated. In Rails 2 :
    task :task_name, :argument_name, :needs => :environment do |t,args|
        # ...
     end

    In Rails 3, you have to do the following:

    task :task_name, [:argument_name] => :environment do |t,args|
        # ...
     end
  15. params[:path] used to be an array of the path split by slash. e.g. you might see the value as ['user', 'details.html'], now it is a string /user/details. Note that params[:path] doesn’t contains the format.
  16. interpreate_status is not in use any more. You can use Rack::Utils::HTTP_STATUS_CODES[status_code] to do the same thing.
  17. Mailer API changes. In Rails 2, you would call deliver_welcome_email or create_welcome_email. This has been deprecated in Rails 3.0 in favour of just calling the method name itself. So you can call Mailer.welcome_email.
  18. Mail API changes. In Rails 2 you define a mailer like below (this example is copied from rails guide)
    class UserMailer < ActionMailer::Base
      def welcome_email(user)
        recipients    user.email
        from          "notifications@example.com"
        subject       "Welcome to My Awesome Site"
        sent_on       Time.now
        body          {:user => user, :url => "http://example.com/login"}
      end
    end

    However in Rails 3 above codes has to be changed to below:

    class UserMailer < ActionMailer::Base
      def welcome_email(user)
        @user = user
        @url =  "http://example.com/login"
        mail(
            :to            => user.email
            :from       =>    "notifications@example.com"
            :subject    =>   "Welcome to My Awesome Site"
            :date        =>       Time.now
        )
      end
    end
  19. If a action name is not defined in the controller but the corresponding views file exists, in Rails 2, it will call method_missing. However in Rails 3, it won’t call method_missings. Thus in the help controller we can’t use the method_missing to dynamic rendering the views.

 

I love Rails Console. If there is anything wrong with my Rails application, I can simply fire the console, and debug from there. Rails makes the query to db very simple and elegant by providing us the ActiveRecord. However, sometimes you may want to know the underlying raw sql statement being sent to the database to see if there is any problem. Especially your rails app is being quite slow, you may want to check if this could be the problem.


So you know that under development mode, the log would print out the raw sql statements executed. What about Rails Console. By default, if you typed in any code that queries the database, it would simply return the objects back to you. You can do the following in order to show the raw sql statements:


Immediately after you have entered Rails Console, typed in the following code in console:


ActiveRecord::Base.logger = Logger.new(STDOUT)

After that, it should print out the sql queries.

If you expect a database table to grow very large, then you will often create some index on the columns that are used to be searched quite often. E.g. if you have a user table, usually you will create index on the user_id column, as usually you will query the table to check if a user_id exists in database. The benefit of using an index for database table is quite true when the table is large although it has some disadvantage as well, like slower update/new record operation due to the needs to update the index file and it takes up extra disk space as well.

 

If no index exists on a table, a table scan must be performed for each table referenced in a database query. The larger the table, the longer a table scan takes because a table scan requires each table row to be accessed sequentially. Although a table scan might be more efficient for a complex query that requires most of the rows in a table, for a query that returns only some table rows an index scan can access table rows more efficiently.

 

The optimizer chooses an index scan if the index columns are referenced in the SELECT statement and if the optimizer estimates that an index scan will be faster than a table scan. Index files generally are smaller and require less time to read than an entire table, particularly as tables grow larger. In addition, the entire index may not need to be scanned. The predicates that are applied to the index reduce the number of rows to be read from the data pages. – extracts from the IBM website.

 

So when it comes to rails, how do you create index using active record migration?

In order to create database index for a certain table, you might have done the following under active record database migration file before.

def self.up
  create_table :table_names do |t|
     t.string :user_id
     t.index :user_id, :unique => true
  end
end

Although you may be able to find the index function API under rails API page.However, the index won’t be created as expected for you. The right way to create an index is using method add_index after you have created the table .

def self.up
  create_table :table_name do |t|
     t.string :user_id
  end
  add_index :table_name, :user_id, :unique => true
end

index function is only available when doing change_table call. So you can also do the following to create the index:

def self.up
   change_table :table_name do |t|
      t.index :user_id, :unique => true
   end
end

So that is to say an index can be created only when the table is created.
Read the rest of this entry »

Today I ran into a problem when trying to connect to mysql database to download some data using Rails 2. I install mysql using macports. After install mysql, i install mysql gem using the following command:

gem install mysql

This actually installed the latest mysql gem 2.8.1. However, when I run my project in production mode to connect to mysql I get the following error:

uninitialized constant MysqlCompat::MysqlRes

It turns out that mysql 2.8.1 driver seems to have a problem. So to fix this, you should do the following to install mysql 2.7.

export ARCHFLAGS=”-arch i386 -arch x86_64″ ;sudo gem install –no-rdoc –no-ri -v=2.7 mysql — –with-mysql-config=/opt/local/bin/mysql_config5

Do replace the mysql-config to the real configuration path in your os.

For more information do checkout the discussion at StackOverflow

Here is how you can use gmail as free SMTP server so that you can use it to send emails in rails application for free.

1. You have to install the actionmailer-tls plugin into your rails project

Gmail only support SSL SMTP mailing service. So if you can’t create a SSL connection to its SMTP server, you can’t send emails through them. This plugin is created to solve this problem.

2. Change your environment.rb

First you have to make sure the plugin is loaded. At the end of the environment.rb, put the following:

require 'smtp_tls'

3. Add mailer configuration
You can put this in environment.rb or environments/development.rb or environments/production.rb depends on which environment you want to use this mailing function.

config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :address => "smtp.gmail.com",
    :port => 587,
    :authentication => :plain,
    :domain => INSERT_MAIL_DOMAIN,
    :user_name => INSERT_MAIL_ADDRESS,
    :password => INSRT_MAIL_PASSWORD
  }

Now trying sending emails with your rails application. Now depends on your ruby version, you may see the following errors:

ERROR ArgumentError: wrong number of arguments (3 for 2)
FILE config/initializers/smtp_tls.rb, line 8

This is obvious that the function check_auth_args is expecting 2 argument, while 3 is given. So let’s fix it:

#check_auth_args user, secret, authtype if user or secret
if RUBY_VERSION > "1.8.6"
  check_auth_args user, secret # for rails 1.8.7
else
  check_auth_args user, secret, authtype if user or secret # for rails 1.8.6
end

Now you should be able to send emails, however, gmail has a 500 mails/day limit. In this case, you may set up multiple accounts, and rotate the settings when sending email error is caught.