Best ruby-on-rails questions in December 2011

What are good reasons to write a web application in Sinatra over Rails, particularly for someone who's spent a lot of time learning Rails?

7 votes

What are good reasons to write a web application in Sinatra over Rails, particularly for someone who's spent a lot of time learning Rails?

I've been doing Rails for 2 years and I do like Rails. But it hurts not knowing if I'm missing out on something that could be really useful for my upcoming project.

Good reasons may include but are not limited to:

  • Cost of development
  • Situational scenarios
  • Performance
  • Features
  • Flavor

Generally speaking, Sinatra is a lot simpler and "to the metal" than Rails. Most of the things Rails gives you out of the box are missing from Sinatra, which, depending on the project, can be a good (or a bad) thing.

A big part of those things can then be re-added to Sinatra through Rack middleware or Sinatra plugins. There's literally heaps of this stuff, in varying quality. If you do things right, your application has a good chance of being a whole lot more flexible and light-weight than its Rails counterpart, but you will be dealing with more upfront boilerplate effort (well, once again depending on the type of project.)

Then there's the Padrino framework, which is essentially Sinatra plus a default set of extensions/middleware/etc. to make development a bit more Rails-like. It's fun to work with, but I feel it sort of makes you miss out on the respective advantages of both Rails or Sinatra.

If you often end up in situations where the Rails defaults (or "the Rails way" of doing things) are not what you'd like to do in your project, or are simply too much or heavy-weight, then Sinatra is definitely worth a look.

(On a side note, I am currently preparing a series of Ruby/Rails development workshops, and will delve into Sinatra with my students before starting with Rails, since its to-the-metal nature makes learning about and understanding the design decisions made in Rails a whole lot easier.)

Edit: I sort of forgot to answer your actual question. Ha!

You may be better off with Sinatra if:

  • you want higher performance (due to the simple reason Sinatra does less than Rails)
  • you want to be more flexible about your technology choices
  • you're looking at evented/concurrent/asynchronous execution (async_sinatra, nom!)
  • you're really, really serious about making modular applications (for example, you can mount a complete Sinatra app on top of your Rails app, and other stunts)
  • your application is first and foremost an API
  • you have some pretty exotic requirements for your routing (even though Rails 3 is now a lot more flexible and forgiving in that regard)
  • you want to learn how Rails, Rack etc. work

Don't use Sinatra if:

  • you absolutely require heaps of good literature (working with Sinatra and specifically Rack will require you to browse vendor source code every now and then)
  • you have a team that works better with the kind of constraints and conventions Rails gives you
  • you're perfectly happy with Rails (or at least you feel the Rails defaults, performance, paradigms etc. are a good fit for your project)

HTH.

In Rails, what is the best way to compact a hash into a nested hash

6 votes

Say I have this:

[
  { :user_id => 1, :search_id => a},
  { :user_id => 1, :search_id => b},
  { :user_id => 2, :search_id => c},
  { :user_id => 2, :search_id => d}
]

and I want to end up with:

[
  { :user_id => 1, :search_id => [a,b]},
  { :user_id => 2, :search_id => [c,d]}
]

What is the best way to do that?

Very strange requirement indeed. Anyway

[ { :user_id => 1, :search_id => "a"},
  { :user_id => 1, :search_id => "b"},
  { :user_id => 2, :search_id => "c"},
  { :user_id => 2, :search_id => "d"} ] \
    .map{ |h| h.values_at(:user_id, :search_id) } \
    .group_by(&:first) \
    .map{ |k, v| { :user_id => k, :search_id => v.map(&:last) } }

Ruby way to Check for string palindrome

6 votes

I wanted to check if a string is palindrome or not using ruby code.

I am a starter in ruby so not too aquainted with the string methods in ruby

def check_palindromic(variable)
  if variable.reverse == variable #Check if string same when reversed 
    puts "#{ variable } is a palindrome."
  else # If string is not the same when reversed
    puts "#{ variable } is not a palindrome."
  end
end

remove duplicate elements from array in ruby

5 votes

I have an array and i have duplicate elements in it.

array = [1,2,2,1,4,4,5,6,7,8,5,6]

How can i remove all the duplicate elements from this array and retain all unique elements without using for loop and iteration?

Very simple

array = array.uniq

The uniq method removes all duplicate elements and retains all unique elements in the array.

That's the beauty of the Ruby language.

Difference between an it block and a specify block in RSpec

5 votes

What is the difference between an it block and a specify block in RSpec?

subject { MovieList.add_new(10) }

specify { subject.should have(10).items }
it { subject.track_number.should == 10}

They seem to do the same job. Just checking to be sure.

The methods are the same; they are provided to make specs read in English nicer based on the body of your test. Consider these two:

describe Array do
  describe "with 3 items" do
    before { @arr = [1, 2, 3] }

    specify { @arr.should_not be_empty }
    specify { @arr.count.should eq(3) }
  end
end

describe Array do
  describe "with 3 items" do
    subject { [1, 2, 3] }

    it { should_not be_empty }
    its(:count) { should eq(3) }
  end
end

Working on a legacy Rails application

5 votes

I have a very old and poorly written Rails app. There are about 9000 lines of code and zero tests. Most of the code is in controllers, and even worse, there are tons of external API calls, system calls to random scripts, etc.

There is also no development environment, everything is set up to work against the production databases. Well not just one database, there are about 10 different databases, since the app is kind of admin backend for a larger site.

My first idea was to get at least somewhat decent test coverage around the parts that I'm going to work on, but I'm unable to get the thing working anywhere else than on the production servers.

Also there are tons of old gems and deprecated warnings, but I can't even think about upgrading the gems until there are tests. Rewrite of the whole up is not an option, and I'm going to have to add/change stuff soon.

I'm not really sure how to approach testing such an app, since there's just so much stuff that can go wrong. What I'd really like to do, is to write some integration tests and then start refactoring, but I can't do that on a production environment.

Writing unit tests with bunch of stubs and mocks doesn't seem that helpful, since the code I'm going to work on basically has to be rewritten from scratch.

What are some steps I can take to basically duplicate a hugeass complex production environment on my development machine, so I can do stuff in isolation?

edit: A little fun fact about the app. When I tried to run it for the first time, it kept on freezing without any error messages ... until about a half hour later I found out, that the timeout to connecting to a database (which wasn't available) was set to 90 minutes!

So this is a relatively new / rare occurrence, because rails "LEGACY" applications are not too popular yet (still pretty young).

However, I have come across a few different writings about how to test (untested) legacy rails applications. A few that I recommend are:

  1. This slideshare
  2. Chapter 18 of "Rails Test Presciptions" from Pragmatic Programmers.

The ultimate and most important thing is to get SOME sort of a test harness working. This means getting factories working, getting your test database working, getting rake running (even if that means stripping out broken tests). From that point, you go back and test modules as you need them, as well as MAKING SURE you are testing all new pieces of code you add to the project.

This is a hugely painful task, and I applaud you for looking to do it the right way.

Cheers!

How to automatically link to objects in text submission in Rails

5 votes

So, you're in Github filing an issue and you refer to issue #31. Then, while writing this issue, you note that @johnmetta has suggested some possible solutions that he's working on. Then you hit "Submit New Issue" and when you do, "#31" and "@johnmetta" are links, and @johnmetta has been notified, and issue #31 has a notification that it has been referenced.

I realize that there are more than one technologies at work here (Javascript goodies, etc), but what I'm looking for are some examples of how to do this type of thing in the Rails world. It's an interestingly difficult subject to search for.

What I've come up with conceptually is:

  1. Have some identifier, such as # or @ that is reserved
  2. Upon submission, search for that identifier in the appropriate attribute
  3. Upon finding it, search for the appropriate model with a field matching what follows
  4. Once finding that, replace that text string with a link
  5. Optionally, do whatever necessary to notify the referenced object

That said, it seems like it's super simple (explicitly coded, assumes friendly_id).

def prettify_user_links(str, source):
  result = str
  str.scan(/(@\S+)+/).each do |mtch|
    # Strip off whatever identifier we're using
    search_string = mtch[0].gsub('@','')
    # Search for the matching model in the appropriate table
    user = User.find(search_string)
    if user
      # If we find a matching model, create some link text and link it
      link_txt = "<a href=>'#{user.url}'>#{mtch}</a>"
      result.gsub!(search_string, link_txt)
      # Notification. Not sure how/where, maybe with a message bus, or something more brute-force like
      Comment.create :user_id => user.id, :body => "You have been mentioned in #{link_to comment.excerpt, comment} by #{link_to comment.owner, owner}"
  return result

That would be my first cut, but I feel there have to be much more elegant solutions.

An additional aspect to this question: How would you grab a snippit of surrounding text. The brute force way would be to search n words before and m words after that string and grab all of that, then grab that sub-string from the results and do the search. Still, seems like there'd be a more elegant solution.

What you've described is the basic way; anything else is not terribly more elegant. It's helpful to see it as two parts: one is on receipt of the comment (when you should do notifications) and the other is on display of the comment, when you should do linkification.

This allows you to keep the original comment in its original form, which is helpful.

Perhaps put an after_create (so notifications aren't sent on every edit) on the comment model (assuming a comment model that includes a 'body' field):

[edit: added contextual info]

after_create :notify_mentions

def notify_mentions
  body.scan %r{(.{0,40})@(\w+)(.{0,20})} do |match|
    username = match[1]
    context = [match.first, match.last]
    Notification.send(match, context, self) if User.exists?(:login => username)
  end
end

I use \w+ in place of \S+ because people often say things like:

Hey @JohnMetta, how are you doing?

and \S+ will capture the , which might be wrong. Pulling the @ out of the capture group lets me ignore it during notification.

The context in the above match groups consists of the 40 characters before and 20 characters after the matched username for your snippet. Adjust to taste.

Then when displaying the message, you essentially create a helper something like what you had:

def linkify(body)
  body.gsub %r{@\w+} do |match|
    link_to match, :controller => :users, :action => :show, :id => match
  end
end

#gsub is awesome like that, in that it takes a block and replaces with the contents.

It's not a lot more elegant than what you had, but it should give a pretty decent result.

How do I correctly set the routes on an ajax button_to?

4 votes

I have implemented an ajax-based button to add and remove a calendar event from a user's "wish list". The button behaves as a toggle-switch. If the event is already on their wish list, it will remove it; if it is not, then it will add it.

My issue is that the button works correctly when the page is first loaded, but after clicking it and replacing it with a new button_to via AJAX, it no longer works.

I looked at this post but he has a slightly different architecture and I am not looking to completely refactor this just yet if I can avoid it. I have a separate model for the saved events. There are three models that come into play here: users, events, and saved_events. There is a many-to-many relationship between users and events which is represented as a saved_event. Here is the relevant code from the models.

user.rb:

  has_many :saved_events
  has_many :events, :through => :saved_events

event.rb:

  has_many :saved_events
  has_many :watchers, :class_name => "User", :through => :saved_events, :source => :user

saved_event.rb:

  belongs_to :event
  belongs_to :user

I have configured pretty standard routes.

routes.rb:

  resources :saved_events, :only => [:index,:create,:destroy]
  resources :users
  resources :events

I initially want to see this button an an event's page, so I added it to the event's show.html.erb. (I realize this isn't quite DRY yet - I am waiting until it works correctly to move it into a partial)

events/show.html.erb:

  <% if !@is_watched %>
    <%= button_to "Add to Wishlist", { :action => 'create', :controller => 'saved_events', :id => @event.id }, :remote => true %>
  <% else %>
    <%= button_to "Remove from Wishlist", saved_event_path(@event), :remote => true, :method => 'delete' %>
  <% end %>

events_controller.rb:

  def show
    @event = Event.find(params[:id])
    @is_watched = @event.watchers.exists?(current_user) if !current_user.nil?

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @event }
      format.json { render :json => @event }
    end
  end

saved_events_controller.rb:

  def create
    logger.debug params.to_yaml

    @event = Event.find(params[:id])

    if !current_user.events.exists?(params[:id])
      current_user.events << @event
    end

    respond_to do |format|
      format.js
    end
  end

  def destroy
    logger.debug params.to_yaml

    @event = current_user.events.find(params[:id])
    current_user.events.delete(@event)

    respond_to do |format|
      format.js
    end
  end

My goal with the ajax was just to swap out the add form with the remove form (or vice-versa). So I have a create.js.erb and a destroy.js.erb which just use the same code from events/show.html.erb.

saved_events/create.js.erb:

$(".button_to").html("<%= escape_javascript button_to "Remove from Wishlist", saved_event_path(@event), :remote => true, :method => 'delete' %>");

saved_events/destroy.js.erb:

$(".button_to").html("<%= escape_javascript (button_to "Add to Wishlist", { :action => 'create', :controller => 'saved_events', :id => @event.id }, :remote => true) %>");

This is what I see in the log if the second button click is to "remove"

Started DELETE "/saved_events?id=1" for 127.0.0.1 at 2011-12-02 11:56:58 -0600

ActionController::RoutingError (No route matches [DELETE] "/saved_events"):

This is what I see in the log if the second button click is to "add"

Started POST "/saved_events/1" for 127.0.0.1 at 2011-12-02 11:59:12 -0600

ActionController::RoutingError (No route matches [POST] "/saved_events/1"):

On initial load of the page, the add button has "/saved_events?id=1" as its action, so I am confused as to why it would be "/saved_events/1" for the second button click.

It seems the issue was from my jquery. I needed to wrap the form in a div, and then call jquery.html() on that div rather than the form itself. I did some other refactoring in the controllers, which I won't post here for brevity, but here are my new js.erb files:

create.js.erb:

<% button_html = button_to( 'Remove from Wishlist', { :action => 'destroy', :id => @saved_event.id }, :remote => true, :method => 'delete' ) %>
$("#toggle_wishlist").html("<%= escape_javascript( button_html ) %>");

destroy.js.erb:

$("#toggle_wishlist").html("<%= escape_javascript( button_to("Add to Wishlist", { :action => 'create', :controller => 'saved_events' }, :remote => true)) %>");
$("#toggle_wishlist .button_to").append("<%= escape_javascript( hidden_field_tag :event_id, @event.id ) %>");

Can I use html tags in twitter-bootstrap popover data-content?

4 votes

I'm using Twitter-Bootstrap within a Rails 3.1.3 application. I have numerous elements with popovers like:

<a data-original-title="Quality" rel="popover" data-content="Did they do a good job?  5 for Really Nice, 4 for Good Enough, 3 for Average, 2 for Somewhat OK, 1 for Really Bad">Q</a>

I'd like to have an ordered list in the content section similar to:

<OL reversed="reversed">
  <LI> for Really Nice </LI>
  <LI> for Good Enough </LI>
  ...
</OL>

Is there a simple way to do this without modifying the JavaScript? Whatever I try, the html code is displayed on the browser instead of being interpreted as such.

UPDATE

Using the following code per David's suggestion

link_to 'Q', '#', options: { data-original-title: "Quality", rel: 'popover', data-content: "Did they do a good job? <ol><li> for Really Nice </li><li>...</li></ol>".html_safe }

generates a syntax error with my setup. I think this explains why: Ruby 1.9 hash with a dash in a key . So I'm using:

<%= link_to 'Q', '#', options: { :"data-original-title" => "Quality", :rel => 'popover', :"data-content" => "Did they do a good job? <ol><li> for Really Nice </li></ol>".html_safe } %>

This doesn't work. It generates the following HTML:

<a href="#" options="{:&quot;data-original-title&quot;=&gt;&quot;Quality&quot;, :rel=&gt;&quot;popover&quot;, :&quot;data-content&quot;=&gt;&quot;Did they do a good job? &lt;ol&gt;&lt;li&gt; for Really Nice &lt;/li&gt;&lt;/ol&gt;&quot;}">Q</a>

You need to create a popover instance that has the html option enabled (place this in your javascript file after the popover JS code):

$('.popover-with-html').popover({ html : true });

Then the link syntax would be:

<%= link_to('Q', '#', :class => "popover-with-html", :title => "Quality", "data-content" => "#{some_content_object.html_safe}") %>

If you're dynamically generating the content, then you need to use html_safe like David suggested so Rails doesn't escape the HTML code. Otherwise, you can just place HTML directly within that content attribute.

What is the difference between "x IS NULL" and "NOT (x IS NOT NULL)"?

4 votes

Is there a significant difference in postgresql's execution, performance, or logic between

SELECT "users".* FROM "users"  WHERE ("users"."deleted_at" IS NULL)

and

SELECT "users".* FROM "users"  WHERE (NOT ("users"."deleted_at" IS NOT NULL))

Obviously, if written by hand, the first expression is the one I would write (who would intentionally write a double negative?!). But in this case, I'm using ruby's arel library to dynamically create both versions, sort of like so:

def generate_query(search_terms, negated=false, users=User)
  where_clause = arel_for_one_of_many_possible_queries(search_terms)
  where_clause = where_clause.not if negated
  users.where(where_clause)
end

And, for the "deleted" search_term, the where_clause will be arel_table[:deleted_at].not_eq(nil), but for other search_terms it could be a variety of clauses, including compound clauses and subselects. Adding the .not to the end, arel will always generate SQL of the second form. I could generate the first form by special casing my NULL checks and manually generating .eq or .not_eq as the case may be, but I'd want some clear benefit to doing that before I make my code more verbose.

Use EXPLAIN to see the difference, if there is any.

I think the query rewriter will optimize this, but I didn't check the source code for this example.

Edit: I was wrong, this is not optimized at all. Where ("users"."deleted_at" IS NULL) can use an index, the (NOT ("users"."deleted_at" IS NOT NULL)) condition results in a sequential disk scan.

Perform Load Test for RoR 2.1 Web Application & Server

4 votes

I have a web application on RoR 2.1 and backend MySQL up and running with around 8k users and now i want to do a Load Test on my web app and server to figure out the load on the server and the average and peak number of concurrent users.

What are the ways of implementing this load test to analyse the load on the server and performance of the web application with a way to figure out average and peak number of concurrent users?

I'm using ab (apache benchmarks http://httpd.apache.org/docs/2.0/programs/ab.html) for load tests. Example of testing on google.com:

ab -n 10000 -c 100 http://google.com/

It allows me to investigate how much requests per second my setup(application) can do as well as concurrency level.

The ab tool is a part of the Apache httpd package in CentOS and Red Hat distributions. So it is probably already installed there. For Ubuntu/Debian install apache2-utils package.

ab --help for full options list

The most important are :

-n requests     Number of requests to perform
-c concurrency  Number of multiple requests to make

Also i'm monitoring peaks of activity with munin(http://httpd.apache.org/docs/2.0/programs/ab.html) and plugins for nginx/passenger/unicorn/CPU/Memory depending on configuration, as well as plugin for MySQL which shows total amount of queries per second and many more data.

You can install munin using appropriate tutorial for your RH linux from that page http://munin-monitoring.org/wiki/LinuxInstallation.

Here also quite nice article about munin and mongrel monitoring: http://onrails.org/2007/08/31/monitoring-rails-performance-with-munin-and-a-mongrel

You could pick up plugins for apache(and not only) monitoring from the http://exchange.munin-monitoring.org.

Good thing about that all that it doesnt require to change application. So you can just install it and use without any changes from your production setup.