Jul 25, 2011

Delayed Job with RSpec

In your test code, just use this line to execute delayed job:


Delayed::Worker.new.work_off

Jul 20, 2011

Rails 3 Madness

I have been struggling with Rails 3 testing framework for a few days now.

This is a madness. There are so many gems to install:

gem 'rspec', :group => [:development, :test]

gem 'rspec-rails', :group => [:development, :test]
gem 'database_cleaner', :group => :test
gem 'factory_girl_rails', :group => :test
gem 'mongoid-rspec', :group => :test

gem 'cucumber-rails', :group => :test
gem 'capybara', :group => :test

gem 'win32-process', :group => :test
gem 'spork', :git => "https://github.com/timcharper/spork.git", :group => :test


rspec-rails is obvious. It is RSpec for Rails.
database_cleaner is for truncate database. It supports Mongoid. That's why I use it.
factory_girl_rails is a mocking library for Rails. It's so simple.
mongoid-rspec is an adapter of RSpec to Mongoid.
cucumber-rails is a BDD testing framework for Rails.
capybara is for testing AJAX and javascript. It can fire an event click on a button or check if the result HTML contains some specific values.
Spork preloads the Rails environment, so that the testing runs faster.

Now you'll need to install RSpec

rails generate rspec:install


Before you run spork, you'll have to make some changes to application.rb in order to make Spork automatically reload any changes


class Application < Rails::Application
.
.
.

if Rails.env.test?
initializer :after => :initialize_dependency_mechanism do
ActiveSupport::Dependencies.mechanism = :load
end
end

end


And in spec_helper.rb, we put this line at the bottom of Spork.prefork block:


ActiveSupport::Dependencies.clear


And in Spork.each_run block, we put in these lines:


load "#{Rails.root}/config/routes.rb"
Dir["#{Rails.root}/app/**/*.rb"].each { |f| load f }


Now you can start Spork

bundle exec spork --bootstrap

bundle exec spork



Related links: https://github.com/RailsApps/rails3-mongoid-devise/wiki/Tutorial

Jul 18, 2011

Eccentric Mongoid behaviour

If you field's suffix is _id or _ids, when you make a query, it will turns your querying string into BSON::ObjectId automatically.

Therefore, please beware.

Jul 17, 2011

Add custom field to sunspot

In schema.xml, we add certain tags:


<types>
<fieldType name="autosuggest" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.LetterTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="25" />
<filter class="solr.ThaiWordFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.LetterTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
</types>

<fields>
<dynamicField name="*_as" type="autocomplete" indexed="true" multiValued="true" stored="false"/>
<dynamicField name="*_ass" type="autocomplete" indexed="true" multiValued="true" stored="true"/>
</fields>


Please note that *_ac is for non-stored field and *_acs is for stored fields. It's just how Sunspot stores fields and we have to follow the convention.

And then in Sunspot's model, we would like to force it to use the new field:

class Tag
.
.
.

include Sunspot::Mongoid
searchable do
text :name, :as => :name_ac

end

end

Jul 13, 2011

Sunspot Solr startup problem on Windows

There is an error on Windows because command-line arguments are escaped in a wrong way.

This fix works for me:http://www.trdev.co.uk/2011/07/03/sunspot-and-solr-search-on-windows-7-errors/

Basically, we just go to sunspot gems in Ruby and change this file:

sunspot/lib/sunspot/server.rb

and do this patch

command << "-Xms#{min_memory}" if min_memory

command << "-Xmx#{max_memory}" if max_memory

command << "-Djetty.port=#{port}" if port

- command << "-Dsolr.data.dir=#{solr_data_dir}" if solr_data_dir

- command << "-Dsolr.solr.home=#{solr_home}" if solr_home

- command << "-Djava.util.logging.config.file=#{logging_config_path}" if logging_config_path

+ command << "-Dsolr.data.dir=\"#{solr_data_dir}\"" if solr_data_dir

+ command << "-Dsolr.solr.home=\"#{solr_home}\"" if solr_home

+ command << "-Djava.util.logging.config.file=\"#{logging_config_path}\"" if logging_config_path

command << '-jar' << File.basename(solr_jar)

FileUtils.cd(File.dirname(solr_jar)) do

- exec(Escape.shell_command(command))

+ exec(command.join(" "))

end

end

Rename muliple files, remove prefix on linux


for f in $(ls uploads__*); do mv "${f}" "${f#uploads__}";done

Jul 12, 2011

Rails 3 strangely turns the 8th field of MySql into a BigDecimal

Please see my post: http://stackoverflow.com/questions/6646507/activerecord-in-rails-3-0-3-turns-the-8th-field-of-mysql-into-a-bigdecimal-how-t

I still cannot solve this problem.


-----------

I can solve it now. It is just a mismatch version between MySQL database and client.

Rails 3, RoutingError crashes the server

I have encountered this weird behavior. It took me 6 consecutive hours to solve it by debugging the whole Rails code.

In this post, someone suggests that we switch from WEBrick to Mongrel.

I have found out that the code piece which causes the problem is (It is located in C:\Ruby192\lib\ruby\gems\1.9.1\gems\railties-3.0.9\lib\rails\rack\log_tailer.rb):


module Rails
module Rack
class LogTailer
.
.
.

def tail!
@file.seek @cursor

if !@file.eof?
contents = @file.read
@cursor = @file.tell
$stdout.print contents
end
end
end
end
end


If you blank this method, WEBrick works fine again. I have done an intensive test on it with a lot of RoutingError thrown.

You can use this patch. Put it in the environment file:



module Rails
module Rack
class LogTailer

def tail!

end
end
end
end


The downside of this is that you won't see debug messages on your console.

To bypass this problem, you can use log4r to output debug messages on console instead.

Work like a charm for me.

Jul 11, 2011

Install MySql2 properly on Windows for Rails 3

You will need to configure your Bundle to use some flags by:


bundle config build.mysql2 --with-mysql-lib="C:\xampp\mysql\lib\opt" --with-mysql-include="C:\xampp\mysql\include"


If you cannot find lib\opt and include folder, please install MySql Connector/C. The folders will be there.

Then you must use mysql2 version 0.2.6 for Windows. Other versions do not work.

In your Gemfile, you should have this:


gem 'mysql2', '0.2.6'


And then you can run:


bundle install (or update)


This will solve all your problems, including "incompatible character encodings: UTF-8 and ASCII-8BIT".

Jul 9, 2011

Ruby global variable cheat sheet

$name program-defined global variable
$! latest error message
$@ location of error
$_ string last read by gets
$. line number last read by interpreter
$& string last matched by regexp
$~ the last regexp match, as an array of subexpressions
$n the nth subexpression in the last match (same as $~[n])
$= case-insensitivity flag
$/ input record separator
$\ output record separator
$0 the name of the ruby script file
$* the command line arguments
$$ interpreter's process ID
$? exit status of last executed child process

Rails plugin init.rb technique

Never ever do this in your init.rb


require 'db_migration'


Sure, Rails will automatically look into your plugin lib folder. But if another file with identical name is loaded before (from other plugin), then Rails won't look anywhere. It'll just grab that file.

Of course this is a behaviour that you don't want. You'd like each plugin to have its own space. Then, do this:


File.dirname(__FILE__)+'/lib/db_migration'

Jul 8, 2011

Rails Patch to obtain a current template

There are 3 types of rendering: Normal, Partial, and Layout.

We have to hook all 3 types.

The template is stored in @last_template.



module ActionView::Rendering
alias_method :_render_template_original, :_render_template
def _render_template(template, layout = nil, options = {})
@last_template = template
_render_template_original(template, layout, options)
end
end





module ActionView::Layouts
alias_method :_render_layout_original, :_render_layout
# Contains the logic that actually renders the layout.
def _render_layout(layout, locals, &block) #:nodoc:
@last_template = layout

_render_layout_original(layout, locals, &block)
end
end





module ActionView::Partials
alias_method :_render_partial_original, :_render_partial

def _render_partial(options, &block) #:nodoc:

prefix = self.controller_path unless options[:partial].include?(?/)
@last_template = self.find_template(options[:partial], prefix, true)

_render_partial_original(options, &block)

end

end

Stupid Rails3 with Missing template and render_to_string on partial view


render :json=>{:ok=>true ,:new_row=>render_to_string(:partial=>"row",:locals=>{:entity=>entity,:field_set=>SHOW_FIELDS,:is_new=>false}), :entity=> entity}


This gives you a "Missing template" error, even the view exists. I have found that this is because an AJAX request on Rails does not include the view format :html.

In order to fix it, just append .html.


render :json=>{:ok=>true ,:new_row=>render_to_string(:partial=>"row.html",:locals=>{:entity=>entity,:field_set=>SHOW_FIELDS,:is_new=>false}), :entity=> entity}


And it will work.

Stupid Rails 3.0.3

mysql2 version 0.2.6 is the only version compatible with Windows :S