RSS export

Devmen Blog entries

The great ruby shootout

Konstantin Shabanov, 27 Mar 08:34

Konstantin Shabanov

I used benchmark suite from ruby-1.9.3-p125. All tests run on:

  • OS: OSX Lion 10.7.3
  • CPU: 2.3GHz i5
  • RAM: 8Gb 1333 MHz DDR3
  • SSD: OCZ Vertex 3 Max IOPS SATA III 2.5" 120Gb

Implementations:

  • ruby 1.8.7p249 (system ruby)
  • ruby 1.9.3p125
  • ruby 2.0.0dev (2012-02-25 trunk 34796)
  • MacRuby 0.12 (ruby 1.9.2) (Nightly build)
  • maglev 1.0.0 (ruby 1.8.7)
  • rubinius 1.2.4 (1.8.7 release 2011-07-05 JI)
  • rubinius 2.0.0dev (1.9.3 e22ed173 yyyy-mm-dd JI)
  • jruby 1.7.0.dev (ruby-1.9.3-p28) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04-ea)
  • jruby 1.6.7 (ruby-1.8.7-p357) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04-ea)

JRuby was run with the --server -Xinvokedynamic.constants=true flags. Read more...

Keeping binary files in database using mongoDB's GridFS

Konstantin Shabanov, 07 Jul 18:52

Konstantin Shabanov

In my side project I tried to keep all binary files related to it in the database using mongoDB’s GridFS. There are numerous posts about that, but what could stop me to write another one? Main difference is using of rack-gridfs gem for GETting files. If you haven’t do anything yet you need to create new rails project skipping activerecord: Read more...

Additional fields in a group request

Oleg Petrushchenko, 24 Jun 14:14

Oleg Petrushchenko
Consider the solution of simple problem. There are several sites that host articles on various subjects, that has attracted the interest of readers. Readers have the opportunity to leave their comments to any article. There is a common table comments for all sites with the following columns: id, page_id, user_name, body, site, hidden, checked. You must select the last n approved (checked) and visible (not hidden) comments for a particular site (site), and commented article (page_id) should not be repeated.
Make a simple request:
SELECT max (id) as max_id, page_id FROM comments
WHERE site = '# {site}' AND hidden! = 't' AND checked = 't'
GROUP BY page_id ORDER BY max_id DESC LIMIT # {n}
We got a sample of the latest comments (max_id) for each page_id, sorted in descending order and limit the first n results. It's pretty simple. The situation becomes more complicated when we want to know the name of the author (user_name) and text (body) of comment. These fields are not present in our sample. Let's try to include body and user_name into SELECT. Unfortunately, postgres will throw an error and advises to include these fields in the GROUP BY or to apply to them an aggregate function. When these fields in the group we get a few lines for each page_id (that does not suit us), and aggregate functions (such as max(body) or avg(user_name)) for these fields have no meaning.
Well, let's get rid of complex queries, we will use an ORM and scopes. It turns out something like this:
last_comments = []
for_site( site ).visible.checked.order( "id desc" ).each do |c|
  unless last_comments.map( &:page_id ).include?( c.page_id )
    last_comments << c
    break if last_comments.size >= n.to_i
  end
end
This solution works, but not too fast, and does not look too good.
Let's try to continue the search for optimal solutions in google. As a result, we find how you can make such a request exclusively by means of sql:
SELECT c.page_id, c.user_name, c.body FROM comments c,
(SELECT max (id) as max_id, page_id FROM comments
WHERE site = '# {site}' AND hidden != 't' AND checked = 't'
GROUP BY page_id) maxresults WHERE c.id = maxresults.max_id
ORDER BY max_id DESC LIMIT # {n}
Let me explain what we did. First, we assigned the first occurrence of the table comments in query alias c. Then, we have included two components in expression FROM. The first component is the table comments (with the alias c), the second component is the expression SELECT:
SELECT max (id) as max_id, page_id FROM comments
WHERE site = '# {site}' AND hidden != 't' AND checked = 't'
GROUP BY page_id
We assigned the max(id) max_id alias and all SELECT expression maxresults alias.
Finally, we linked the id field between tables, which we call c and maxresults. As a result, we got a request that allow to find out ids of recent comments and moreover the names of authors and texts of these comments. Read more...

Cross domain Ajax with POST support.

Pavel Golubev, 15 Jun 12:46

Pavel Golubev
Most popular ways to implement cross domain Ajax are JSONP and Flash. Although, Flash is not the best choice, since it's not supported on mobile devices, slow and hard to debug. And JSONP does not support POST. So the only possible way to get cross domain POST requests working is using XhrIframeProxy technology. XmlIframeProxy is a mix of <iframe> and XmlHttpRequest. Basic idea is that frames from different domains can communicate within each other via anchors (anchor is a part of URL, which goes after #). Great JQuery plugin postmessage implements XmlIframeProxy. Now first thing you need to do is specify target for your form:
  <iframe name="xhriframeproxy"></iframe>
  <form method="post" target="xhriframeproxy"></form>
When you submit form, the result will be loaded in xhriframeproxy iframe. Next thing is to create callback, which would listen to iframe messages. Let's assume every message is a JSON data, which contains two keys: comments_list and new_comment.
  $.receiveMessage(function(e){
    var obj = $.parseJSON(e.data);
    if (obj.comments_list) 
      $('#comments-list').html(obj.comments_list)
    if (obj.new_comment)
      $('#new_comment').html(obj.new_comment)
  })
When you submit your form, make sure, your response looks like this:
#comments-list= render :partial => "comments/comments", :object => collection
#new_comment= render :partial => "comments/form"
:javascript
  $.postMessage(
    $.toJSON({ 
      'comments_list' : $('#comments-list').html(),
      'new_comment' : $('#new_comment').html(),
    }),
    parent_page_url
  );
So, now you can safely submit your POST form into an iframe, it will render response, splitted into two divs (comments-list and new_comment) and send message to parent page. Parent page receives message, decodes JSON and gets access to server response. You get true cross domain AJAX with POST support. Read more...

Keep views simple

Pavel Chipiga, 15 Jun 06:50

Pavel Chipiga
Some times you need complex logic in views to filter some fields from unregistered users and show default message for blank fields. This case instead of tons if statements you can use nifty helpers with the power of ruby blocks. Like this:
  def hide_field(object, field = nil, &block)
    if current_user # can? :read_fields, object # for cancan fans
      block_given? ? yield : object.send(field.to_sym)
    else
      'hidden'
    end
  end

  def stub_blank(object, &block)
    if object.present?
      block_given? ? yield : object
    else
      'not set'
    end
  end
And now in your views you can use it like this:
hide_field order, :contact_name
hide_field(order) { order.company.name }
stub_blank(order.employees_num)
stub_blank(order.employees_num) { I18n.t(:employee, :count => order.employees_num) }
hide_field(order) { stub_blank order.contact_name }
This small trick can save many lines of code in your views. Enjoy! Read more...