Best ruby-on-rails questions in May 2012

capistrano - NameError: uninitialized constant Net::SSH::KnownHosts::SUPPORTED_TYPE

9 votes

I'm trying to deploy my Rails (3.1.3) application to the preprod env. I use capistrano (2.12.0) and rvm-capistrano (1.2.2).

When I call bundle exec cap ssh it works fine. But when I call bundle exec cap deploy I get the following trace:

$ cap deploy
    triggering start callbacks for `deploy'
  * 18:42:19 == Currently executing `multistage:ensure'
*** Defaulting to `preprod'
  * 18:42:19 == Currently executing `preprod'
  * 18:42:19 == Currently executing `deploy'
  * 18:42:19 == Currently executing `deploy:update'
 ** transaction: start
  * 18:42:19 == Currently executing `deploy:update_code'
  * 18:42:19 == Currently executing `deploy:set_previous_revision'
  * executing "cd /rails_apps/com.example.preprod/current; git rev-parse --short HEAD"
    servers: ["preprod.example.com"]
connection failed for: preprod.example.com (NameError: uninitialized constant Net::SSH::KnownHosts::SUPPORTED_TYPE)

Of course example.com is a placeholder, it doesn't come from a mistake in the capistrano config.

Any idea of what could cause that ?

I'm using RVM with Ruby 1.9.3-p194.

Thanks !

Reverting back from net-ssh 2.5.1 to 2.4.0 seems to solve the problem for now.

Download pdf asynchronously

8 votes

When a user clicks on a links in my Ruby on Rails app, a PDF file is generated in background.

The app is polling the server to know when the PDF file is ready, and then it should ask the user to download it as if he clicked on a PDF link that already existed.

We do this with an hidden iframe and change the src attribute when the PDF file is ready.

While it works on Firefox (there's a native pop up for downloading the file), it does not on safari/chrome. How should I do this? I've seen there's a Content-Disposition HTTP header, but the PDF file is stored on S3, so I don't think I can use that method.

You do need to use the Content-Disposition = 'attachment'; response header.

I'm not totally up to the play with S3 so let me know if this answer isn't quite right but it seems you are able to set the content headers in the request URL now, see example here.

What is the fastest way to render json in rails

7 votes

I'm optimizing some slow transactions in our Rails application and a I see significant time spent rendering JSON views:

Rendered welcome/index.json.rabl (490.5ms)
Completed 200 OK in 1174ms (Views: 479.6ms | ActiveRecord: 27.8ms)

Assuming that the API call is returning exactly the data it needs to return, What is the fastest way to render JSON in rails?

We are using Rabl because of the ability to share code easily, but we aren't tied to it.

Rabl uses multi_json for compatibility across platforms and doesn't use the quite fast Yajl library by default. Rabl's config documentation explains the solution:

# Gemfile
gem 'yajl-ruby', :require => "yajl"

In the event that still isn't performant enough, you might want to explore a different JSON serializer like oj. You could also instrument your render and see where the bottleneck exists.

How can I speed up the creation of 5,000 records for my rspec tests?

7 votes

I am using Ruby on Rails 3.2.2, FactoryGirl 3.1.0, FactoryGirlRails 3.1.0, Rspec 2.9.0 and RspecRails 2.9.0. In order to test my application I have to create a lot of records (about 5000) in the database, but that operation is very slow (it takes more than 10 minutes to create records). I proceed like this:

before(:each) do
  5000.times do
    FactoryGirl.create(:article,)
  end
end

How can I improve my spec code so to go faster?

Note: Maybe the slowness is given by (5) article callbacks that run before and after each article creation process, but I can skip those (since the only things I have to test are articles and not associated models) if those slow creation of records... is it possible to make that and is it the right way to proceed?

Doing it your way Rails creates a transaction for every insert. There are a number of ways to improve your bulk inserts.

Described here:

http://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/

Share session (cookies) between subdomains in Rails?

6 votes

I have an app setup where each user belongs to a company, and that company has a subdomain (I am using basecamp style subdomains). The problem that I am facing is that rails is creating multiple cookies (one for lvh.me and another for subdomain.lvh.me) which is causing quite a few breaks in my application(such as flash messages being persistent though out all requests once signed in).

I have this in my /cofig/initilizers/session_store.rb file:

AppName::Application.config.session_store :cookie_store, key: '_application_devise_session', domain: :all

The domain: :all seems to be the standard answer I found on Google, but that doesn't seem to be working for me. Any help is appreciated!

As it turns outs 'domain: all' creates a cookie for all the different subdomains that are visited during that session (and it ensures that they are passed around between request). If no domain argument is passed, it means that a new cookie is created for every different domain that is visited in the same session and the old one gets discarded. What I needed was a single cookie that is persistent throughout the session, even when the domain changes. Hence, passing 'domain: lvh.me' solved the problem in development. This creates a single cookie that stays there between different subdomains.

For anyone needing further explanation, this is a great link: http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/

State Machine, Model Validations and RSpec

6 votes

Here's my current class definition and spec:

class Event < ActiveRecord::Base

  # ...

  state_machine :initial => :not_started do

    event :game_started do
      transition :not_started => :in_progress
    end

    event :game_ended do
      transition :in_progress => :final
    end

    event :game_postponed do
      transition [:not_started, :in_progress] => :postponed
    end

    state :not_started, :in_progress, :postponed do
      validate :end_time_before_final
    end
  end

  def end_time_before_final
    return if end_time.blank?
    errors.add :end_time, "must be nil until event is final" if end_time.present?
  end

end

describe Event do
  context 'not started, in progress or postponed' do
    describe '.end_time_before_final' do
      ['not_started', 'in_progress', 'postponed'].each do |state|
        it 'should not allow end_time to be present' do
          event = Event.new(state: state, end_time: Time.now.utc)
          event.valid?
          event.errors[:end_time].size.should == 1
          event.errors[:end_time].should == ['must be nil until event is final']
        end
      end
    end
  end
end

When I run the spec, I get two failures and one success. I have no idea why. For two of the states, the return if end_time.blank? statement in the end_time_before_final method evaluates to true when it should be false each time. 'postponed' is the only state that seems to pass. Any idea as to what might be happening here?

It looks like you're running into a caveat noted in the documentation:

One important caveat here is that, due to a constraint in ActiveModel's validation framework, custom validators will not work as expected when defined to run in multiple states. For example:

 class Vehicle
   include ActiveModel::Validations

   state_machine do
     ...
     state :first_gear, :second_gear do
       validate :speed_is_legal
     end
   end
 end

In this case, the :speed_is_legal validation will only get run for the :second_gear state. To avoid this, you can define your custom validation like so:

 class Vehicle
   include ActiveModel::Validations

   state_machine do
     ...
     state :first_gear, :second_gear do
       validate {|vehicle| vehicle.speed_is_legal}
     end
   end
 end

Ruby date equation not returning expected truth value

5 votes

Why do the following differ?

Time.now.end_of_day      == Time.now.end_of_day - 0.days      # false
Time.now.end_of_day.to_s == Time.now.end_of_day - 0.days.to_s # true

Because the number of nanoseconds is different:

ruby-1.9.2-p180 :014 > (Time.now.end_of_day - 0.days).nsec
 => 999999000 
ruby-1.9.2-p180 :015 > Time.now.end_of_day.nsec
 => 999999998 

How to improve performance of single-page application?

5 votes

Introduction
I have a (mostly) single-page application built with BackboneJS and a Rails backend.

Because most of the interaction happens on one page of the webapp, when the user first visits the page I basically have to pull a ton of information out of the database in one large deeply joined query.

This is causing me some rather extreme load times on this one page.

load times

NewRelic appears to be telling me that most of my problems are because of 457 individual fast method calls.

fast methid calls

Now I've done all the eager loading I can do (I checked with the Bullet gem) and I still have a problem.

These method calls are most likely ocurring in my Rabl serializer which I use to serialize a bunch of JSON to embed into the page for initializing Backbone. You don't need to understand all this but suffice to say it could add up to 457 method calls.

object @search
attributes :id, :name, :subscription_limit

# NOTE: Include a list of the members of this search.
child :searchers => :searchers do
  attributes :id, :name, :gravatar_icon
end

# Each search has many concepts (there could be over 100 of them).
child :concepts do |search|
  attributes :id, :title, :search_id, :created_at

  # The person who suggested each concept.
  child :suggester => :suggester do
    attributes :id, :name, :gravatar_icon
  end

  # Each concept has many suggestions (approx. 4 each).
  node :suggestions do |concept|
    # Here I'm scoping suggestions to only ones which meet certain conditions.
    partial "suggestions/show", object: concept.active_suggestions
  end

  # Add a boolean flag to tell if the concept is a favourite or not.
  node :favourite_id do |concept|
    # Another method call which occurs for each concept.
    concept.favourite_id_for(current_user)
  end
end

# Each search has subscriptions to certain services (approx. 4). 
child :service_subscriptions do
  # This contains a few attributes and 2 fairly innocuous method calls.
  extends "service_subscriptions/show"
end

So it seems that I need to do something about this but I'm not sure what approach to take. Here is a list of potential ideas I have:

Performance Improvement Ideas

Dumb-Down the Interface
Maybe I can come up with ways to present information to the user which don't require the actual data to be present. I don't see why I should absolutely need to do this though, other single-page apps such as Trello have incredibly complicated interfaces.

Concept Pagination
If I paginate concepts it will reduct the amount of data being extracted from the database each time. Would product an inferior user interface though.

Caching
At the moment, refreshing the page just extracts the entire search out of the DB again. Perhaps I can cache parts of the app to reduce on DB hits. This seems messy though because not much of the data I'm dealing with is static.

Multiple Requests
It is technically bad to serve the page without embedding the JSON into the page but perhaps the user will feel like things are happening faster if I load the page unpopulated and then fetch the data.

Indexes
I should make sure that I have indexes on all my foreign keys. I should also try to think about places where it would help to have indexes (such as favourites?) and add them.

Move Method Calls into DB
Perhaps I can cache some of the results of the iteration I do in my view layer into the DB and just pull them out instead of computing them. Or I could sync things on write rather than on read.

Question
Does anyone have any suggestions as to what I should be spending my time on?

This is a hard question to answer without being able to see the actual user interface, but I would focus on loading exactly only as much data as is required to display the initial interface. For example, if the user has to drill down to see some of the data you're presenting, then you can load that data on demand, rather than loading it as part of the initial payload. You mention that a search can have as many as 100 "concepts," maybe you don't need to fetch all of those concepts initially?

Bottom line, it doesn't sound like your issue is really on the client side -- it sounds like your server-side code is slowing things down, so I'd explore what you can do to fetch less data, or to defer the complex queries until they are definitely required.

Memory bloat when creating many new objects

5 votes

When I run this and then watch the memory consumption of my ruby process in OSX Activity Monitor, the memory increases at about 3 MB/s.

If I remove the transaction it about halves the memory consumption but still, the memory footprint keeps going up. I have an issue on my production app where Heroku kills the process because of its memory consumption.

Is there a way of doing the below, in a way that won't increase memory? If I comment out the .save line then it's okay but of course this isn't a solution.

ActiveRecord::Base.transaction do
  10000000.times do |time|
    puts "---- #{time} ----"
    a = Activity.new(:name => "#{time} Activity")
    a.save!(:validate => false)
    a = nil
  end
end

I am running this using delayed_job.

The a = nil line is unnecessary and you can remove that.

You're creating a lot of objects every time you loop - two strings, two hashes, and an Activity object so I'm not surprised you're experiencing high memory usage, especially as you're looping 10 million times! There doesn't appear to be a more memory efficient way to write this code.

The only way I can think of to reduce memory usage is to manually start the garbage collector every x number of iterations. Chances are Ruby's GC isn't being aggressive enough. You don't, however, want to invoke it every iteration as this will radically slow your code. Maybe you could use every 100 iterations as a starting point and go from there. You'll have to profile and test what is most effective.

The documentation for the GC is here.

Advanced SQL in Rails

5 votes

I have 2 models

class User < AR
 has_many :friends
end

class Friend < AR
  # has a name column
end

I need to find all Users who are Friends with both 'Joe' and 'Jack'

Any idea how i can do this in rails?

One option is to put each of the names as arguments for individual INNER JOINS. In SQL it would be something like this:

SELECT users.* FROM users
INNER JOIN friends AS f1 
    ON users.id = f1.user_id 
    AND f1.name = 'Joe'
INNER JOIN friends AS f2 
    ON users.id = f2.user_id 
    AND f2.name = 'Jack'

Since it is INNER JOINS, it will only display results where the users table can be joined with both f1 and f2.

And to use it in Rails, maybe do it something like this:

class User < AR
  has_many :friends

  def self.who_knows(*friend_names)
    joins((1..friend_names.length).map{ |n| 
      "INNER JOIN friends AS f#{n} ON users.id = f#{n}.user_id AND f#{n}.name = ?" }.join(" "),
      *friend_names)
    })
  end
end

Which you then can call like this:

@users = User.who_knows("Joe", "Jack")

How can I stop meta_search from defining search on my models?

4 votes

I'm using active_admin and that's bringing in meta_search to my project. (Which I don't want to use for anything else).

It seems to be defining the search method on all my models, which then means when I include tire, I can't use it's search method.

There seems to be something strange with how it's defining the method also - method_defined? says that the search method is not defined, yet when I call it I get the meta_search one. Even if I define my own search method in the class, when I call Document.search I still get meta_search.

EDIT: I'd be interested in general ways of dealing with this sort of thing - I have solved this particular issue by using Model.tire.search (since tire is also accessible that way), but I still hate that a gem I'm not even using can force me to use a workaround in the rest of my project.

EDIT: I don't know of a good way of including code blocks in answers to answers, so I'll put this here.

# Meta_search loaded, tire is not
1.9.3p125 :001 > require "tire"   #=> true
1.9.3p125 :002 > Document.send(:include, Tire::Model::Search)
=> Document(...)
1.9.3p125 :003 > Document.search
  Document Load (2.1ms)  SELECT "documents".* FROM "documents" 
  # I get meta_search, as I should


# Tire loaded (and the include Tire::Model::Search is inside the class definition), meta_search is not loaded
1.9.3p125 :001 > Document.search
# I get tire, as I should
1.9.3p125 :002 > require "meta_search"   #=> true
1.9.3p125 :003 > Document.search
# I still get tire, all is well

# Tire loaded, meta_search is not loaded
1.9.3p125 :001 > require "meta_search"   #=> true
1.9.3p125 :002 > Document.search
  Document Load (1.8ms)  SELECT "documents".* FROM "documents" 
# I get meta_search, even though Document.search was already defined!

# Tire loaded, meta_search is not loaded, RAILS_ENV="production"
Loading production environment (Rails 3.2.2)
1.9.3p125 :001 > require "meta_search"
=> true 
1.9.3p125 :002 > Document.search
# I get tire!

My interpretation of this is that there is a bug with how meta_search detects if search is already defined when the class hasn't actually loaded. Hooray!

the relevant 2 lines:

https://github.com/ernie/meta_search/blob/master/lib/meta_search.rb#L55

https://github.com/ernie/meta_search/blob/master/lib/meta_search/searches/active_record.rb#L46

I don't think it is a bug, it is just how things are.

in scenario 3 In development environment, you do not preload the model. When you require 'meta_search', it will define 'search' on ActiveRecord::Base. Then you say Document, which loads the model, will first inherit defined search method so when it includes Tire search module, it will leave search aliased to metasearch.

In production mode (scenario 4) as well as scenario 2, you preload the document model before metasearch so Tire will define search. Now requiring metasearch will only have effect on newly loaded classes.

You can see that the order in which gems are defined does not count. But you can undefine search method after gem require.

# application.rb
# ...
Bundler.require(:default, Rails.env) if defined?(Bundler)
# now move search out of the way
ActiveRecord::Base.instance_eval { undef :search }

so any time later we load a model class and include tire, search will correctly go to tire, both in development and production.

This is not ideal since the search method for non-tire models will not delegate to metasearch, in fact it will not be defined. So probably the second solution is best: here you overwrite the search method with one which checks for tire at runtime:

class ActiveRecord::Base
  def self.search(*args, &block)
    if respond_to?(:tire)
       tire.search(*args, &block)
    else
       metasearch(*args, &block)
    end
  end
end

does this help?