Archive

Posts Tagged ‘ruby’

Deep associations in rails activerecord

May 22nd, 2010 Comments off

Some time ago I wrote about complex associations, now time to add another method and corrections.

First the finder_by_sql, in that particular case It was necessary to add

:readonly => true

So the code looks now like this:

  has_many :roles, 
    :readonly => true, 
    :finder_sql => '
SELECT roles.name FROM roles
INNER JOIN responsibilities ON roles.id = responsibilities.role_id
INNER JOIN assigments ON responsibilities.group_id = assigments.group_id
WHERE assigments.user_id = #{id}
GROUP BY roles.id
  '

There is one realy big downside of using finder_sql – it does not work with find_by_… or named scopes, so this forced me to continue searching and this is the result:

  def roles
    Role.scoped(
     {
       :joins => { :responsibilities => { :group => { :assigments => :user } } },
       :conditions => {"users.id" => id},
       :group => "roles.id"
     }
   )
  end

and now I can write:

user.roles.by_name(:admin).count

where by_name is an named scope

  named_scope :by_name, lambda { |type| {:conditions => [ "roles.name = ", type.to_s ] } }

Cucumber multi-session

March 2nd, 2010 3 comments

This article is indirect translation of Cucumber – obsluga kilku sesji – polish version (from andrzejsliwa.com devblog).

Most of standard testing related tasks can be achieved in a simple way using the default steps from Cucumber. By assumption Cucumber is for functional testing, but it can also be used to implement integration test. This is especially useful when we want test interaction between users, when they should get on-line notifications – and this should be tested without login/logout functionality, like in shout box which was popular some time ago.

When using integration tests you could use block open_session:

def login(user)
  open_session do |sess|
    sess.extend(CustomDsl)
    u = users(user)
    sess.https!
    sess.post "/login", :username => u.username, :password => u.password
    assert_equal '/welcome', path
    sess.https!(false)
  end
end

But in the case of cucumber which is based on the steps it was necessary to find a solution that is suited to the form in which scenarios are created.

So I have asked my friend Andrzej Sliwa to write an example code, this is the example:

module ActionController
  module Integration
    class Session
      def switch_session_by_name(name)
        if @sessions_by_name.nil? 
          @sessions_by_name = { :default => @response.session.clone }
        end
        @sessions_by_name[name.to_sym] ||= @sessions_by_name[:default].clone
        @response.session = @sessions_by_name[name.to_sym]
      end
    end
  end
end

Given /^session name is "([^\"]*)"$/ do |name|
  switch_session_by_name(name)
end 

Use of this mechanism is trivially easy to perform the following step:

Given session name is "guest no 1 session"

g

In this case, a named session is created which is not dependent on others (including the default). Access to default session is called by using the default name:

Given session name is "default"

You can always get back to named session using the same name as before, the state of it will be persisted for you.

More details on Integration tests: http://guides.rubyonrails.org/testing.html#integration-testing-examples

Categories: Development Tags: , , ,

exception iteration in ruby

January 29th, 2010 Comments off

There are many ways to iterate in ruby, many methods, but going back to assembler roots of mine I found another one:

>> a=[1,2,3]
=> [1, 2, 3]
>> begin puts a.shift; raise unless a.blank?; rescue; retry; end
1
2
3
=> nil

This code is only prof of concept, it should not be used for iterations, by example if it would be used without prior initialization of “a” variable it would be an endless loop as on exception “NameError” it will retry in endless loop.

There are other places where this could be used, but even possible retry should not be used without some kind of endless loop protection like:

>> i=10; begin puts IO.read('some.file'); rescue; if i>0 then puts "#{i} ..."; i-=3; sleep 1; retry; end; end
10 ...
9 ...
8 ...
7 ...
some file created
=> nil

In this example a file was created during run of the command – on second console by just running “echo some file created > some.file”.

There are other ways to do the same, maybe not so cool like that above but probably most of developers will prefer something like:

>> 10.downto(1){|i| begin puts IO.read('some.file'); break; rescue; puts "#{i} ..."; sleep 3; end }
10 ...
9 ...
8 ...
some file created
=> nil

Did You liked this post or maybe not, vote on it at dzone.

Categories: Development Tags: , , ,

string to class in ruby on rails

January 26th, 2010 Comments off

There are few ways to have a class from a string, most know are:

  • Kernel.const_get(‘User’)
  • eval(‘User’)
  • ‘User’.constantize

The order in which I have named them is important – a bit important, Kernel.const_get is 10 times faster then constantize and 5 times faster then eval.

The reason of such speed for Kernel.const_get is from it has to maintain list of all constants in the application, tests show it may even behave faster then storing names and Class mapping in a hash.

The difference is not big on simple calls to create just one or two classes, but on heavy loaded systems this might give some more percents of the hardware.

Did You liked this post or maybe not, vote on it at dzone.

easy capistrano remote invocation

May 6th, 2009 Comments off

Today I was coding just for fun … and wrote my own Capistrano script for deployment, during this I have found great way to invoke remote tasks.

The method is easy, add following code to your config/deploy.rb file:

set :sudo_call, ''
desc 'makes remote/rake calls to be executed with sudo'
task :use_sudo do
  set :sudo_call, 'sudo'
end

desc 'run rake task'
task :rake do
  ARGV.values_at(Range.new(ARGV.index('rake')+1,-1)).each do |task|
    run "cd #{current_path}; #{sudo_call} RAILS_ENV=production rake #{task}"
  end
  exit(0)
end

desc 'run remote command'
task :remote do
  command=ARGV.values_at(Range.new(ARGV.index('remote')+1,-1))
  run "cd #{current_path}; #{sudo_call} RAILS_ENV=production #{command*' '}"
  exit(0)
end

desc 'run specified rails code on server'
task :runner do
  command=ARGV.values_at(Range.new(ARGV.index('runner')+1,-1))
  run "cd #{current_path}; RAILS_ENV=production script/runner '#{command*' '}'"
  exit(0)
end

Now try your new tool with following commands:

cap rake db:migrate
cap use_sudo rake db:migrate
cap remote "tail -n 10 log/production.log"
cap use_sudo remote cat /etc/passwd
cap runner p User.all
cap runner "User.all.each{ |u| p u }"

In the third call I have used parentheses to hide “-n” form Capistrano, because it is its parameter, to see whole list of Capistrano parameters call it with “cap –help”. For the last command I have used parentheses again because now it contained bash special characters.

Did You liked this post or maybe not, vote on it at dzone.

Categories: Development, Linux Tags: , , , ,