Best ruby-on-rails questions in June 2012

Testing: how to focus on behavior instead of implementation without losing speed?

14 votes

It seems, that there are two totally different approaches to testing, and I would like to cite both of them.

The thing is, that those opinions were stated 5 years ago (2007), and I am interested, what has changed since then and which way should I go.

Brandon Keepers:

The theory is that tests are supposed to be agnostic of the implementation. This leads to less brittle tests and actually tests the outcome (or behavior).

With RSpec, I feel like the common approach of completely mocking your models to test your controllers ends up forcing you to look too much into the implementation of your controller.

This by itself is not too bad, but the problem is that it peers too much into the controller to dictate how the model is used. Why does it matter if my controller calls Thing.new? What if my controller decides to take the Thing.create! and rescue route? What if my model has a special initializer method, like Thing.build_with_foo? My spec for behavior should not fail if I change the implementation.

This problem gets even worse when you have nested resources and are creating multiple models per controller. Some of my setup methods end up being 15 or more lines long and VERY fragile.

RSpec’s intention is to completely isolate your controller logic from your models, which sounds good in theory, but almost runs against the grain for an integrated stack like Rails. Especially if you practice the skinny controller/fat model discipline, the amount of logic in the controller becomes very small, and the setup becomes huge.

So what’s a BDD-wannabe to do? Taking a step back, the behavior that I really want to test is not that my controller calls Thing.new, but that given parameters X, it creates a new thing and redirects to it.

David Chelimsky:

It’s all about trade-offs.

The fact that AR chooses inheritance rather than delegation puts us in a testing bind – we have to be coupled to the database OR we have to be more intimate with the implementation. We accept this design choice because we reap benefits in expressiveness and DRY-ness.

In grappling with the dilemma, I chose faster tests at the cost of slightly more brittle. You’re choosing less brittle tests at the cost of them running slightly slower. It’s a trade-off either way.

In practice, I run the tests hundreds, if not thousands, of times a day (I use autotest and take very granular steps) and I change whether I use “new” or “create” almost never. Also due to granular steps, new models that appear are quite volatile at first. The valid_thing_attrs approach minimizes the pain from this a bit, but it still means that every new required field means that I have to change valid_thing_attrs.

But if your approach is working for you in practice, then its good! In fact, I’d strongly recommend that you publish a plugin with generators that produce the examples the way you like them. I’m sure that a lot of people would benefit from that.

Ryan Bates:

Out of curiosity, how often do you use mocks in your tests/specs? Perhaps I'm doing something wrong, but I'm finding it severely limiting. Since switching to rSpec over a month ago, I've been doing what they recommend in the docs where the controller and view layers do not hit the database at all and the models are completely mocked out. This gives you a nice speed boost and makes some things easier, but I'm finding the cons of doing this far outweigh the pros. Since using mocks, my specs have turned into a maintenance nightmare. Specs are meant to test the behavior, not the implementation. I don't care if a method was called I just want to make sure the resulting output is correct. Because mocking makes specs picky about the implementation, it makes simple refactorings (that don't change the behavior) impossible to do without having to constantly go back and "fix" the specs. I'm very opinionated about what a spec/tests should cover. A test should only break when the app breaks. This is one reason why I hardly test the view layer because I find it too rigid. It often leads to tests breaking without the app breaking when changing little things in the view. I'm finding the same problem with mocks. On top of all this, I just realized today that mocking/stubbing a class method (sometimes) sticks around between specs. Specs should be self contained and not influenced by other specs. This breaks that rule and leads to tricky bugs. What have I learned from all this? Be careful where you use mocking. Stubbing is not as bad, but still has some of the same issues.

I took the past few hours and removed nearly all mocks from my specs. I also merged the controller and view specs into one using "integrate_views" in the controller spec. I am also loading all fixtures for each controller spec so there's some test data to fill the views. The end result? My specs are shorter, simpler, more consistent, less rigid, and they test the entire stack together (model, view, controller) so no bugs can slip through the cracks. I'm not saying this is the "right" way for everyone. If your project requires a very strict spec case then it may not be for you, but in my case this is worlds better than what I had before using mocks. I still think stubbing is a good solution in a few spots so I'm still doing that.

I think all three opinions are still completely valid. Ryan and I were struggling with the maintainability of mocking, while David felt the maintenance tradeoff was worth it for the increase in speed.

But these tradeoffs are symptoms of a deeper problem, which David alluded to in 2007: ActiveRecord. The design of ActiveRecord encourages you to create god objects that do too much, know too much about the rest of the system, and have too much surface area. This leads to tests that have too much to test, know too much about the rest of the system, and are either too slow or brittle.

So what's the solution? Separate as much of your application from the framework as possible. Write lots of small classes that model your domain and don't inherit from anything. Each object should have limited surface area (no more than a few methods) and explicit dependencies passed in through the constructor.

With this approach, I've only been writing two types of tests: isolated unit tests, and full-stack system tests. In the isolation tests, I mock or stub everything that is not the object under test. These tests are insanely fast and often don't even require loading the whole Rails environment. The full stack tests exercise the whole system. They are painfully slow and give useless feedback when they fail. I write as few as necessary, but enough to give me confidence that all my well-tested objects integrate well.

Unfortunately, I can't point you to an example project that does this well (yet). I talk a little about it in my presentation on Why Our Code Smells, watch Corey Haines' presentation on Fast Rails Tests, and I highly recommend reading Growing Object Oriented Software Guided by Tests.

Rails "find_all_by" vs ".where"

11 votes

I have the following code:

def maturities
  InfoItem.find_all_by_work_order(self.work_order).map(&:maturity)
end

I was thinking about changing it to:

def maturities
  InfoItem.where(work_order: self.work_order).map(&:maturity)
end

Would there be any advantage to this? It seems like .where is more common than find_all_by nowadays.

My opinion is that using .where is a better approach.

When you use attribute based finders, you are going to have to tunnel through a method missing call and eventually define a class method, via class_eval, that returns your result. This is extra processing that you may not need to do.

Also, stringing together: find_by_this_and_this_and_this_and_this... can get ugly.

See how rails accomplishes attribute based finders here

Method missing from module DynamicMatchers on github:

def method_missing(name, *arguments, &block)
  match = Method.match(self, name)

  if match && match.valid?
    match.define
    send(name, *arguments, &block)
  else
    super
  end
end

Callback denied with OmniAuth

9 votes

When I initiate the logging in process using OmniAuth in a Rails 3 app, if I cancel on the provider's page, I get sent back to an URL that looks something like:

http://example.com/auth/twitter/callback?denied=aUho....

and my application throws a 500, that I can see it's a OAuth::Unauthorized: 401 Unauthorized, without ever touching any of my controller actions.

The stack trace is when I reproduce it in my computer is:

oauth (0.4.6) lib/oauth/consumer.rb:216:in `token_request'
oauth (0.4.6) lib/oauth/consumer.rb:136:in `get_request_token'
omniauth-oauth (1.0.1) lib/omniauth/strategies/oauth.rb:29:in `request_phase'
omniauth-twitter (0.0.11) lib/omniauth/strategies/twitter.rb:50:in `request_phase'
omniauth (1.1.0) lib/omniauth/strategy.rb:207:in `request_call'
omniauth (1.1.0) lib/omniauth/strategy.rb:174:in `call!'
omniauth (1.1.0) lib/omniauth/strategy.rb:157:in `call'
omniauth (1.1.0) lib/omniauth/strategy.rb:177:in `call!'
omniauth (1.1.0) lib/omniauth/strategy.rb:157:in `call'
omniauth (1.1.0) lib/omniauth/builder.rb:48:in `call'
sass (3.1.19) lib/sass/plugin/rack.rb:54:in `call'
warden (1.1.1) lib/warden/manager.rb:35:in `block in call'
warden (1.1.1) lib/warden/manager.rb:34:in `catch'
warden (1.1.1) lib/warden/manager.rb:34:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/best_standards_support.rb:17:in `call'
rack (1.4.1) lib/rack/etag.rb:23:in `call'
rack (1.4.1) lib/rack/conditionalget.rb:25:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/head.rb:14:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/params_parser.rb:21:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/flash.rb:242:in `call'
rack (1.4.1) lib/rack/session/abstract/id.rb:205:in `context'
rack (1.4.1) lib/rack/session/abstract/id.rb:200:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/cookies.rb:338:in `call'
activerecord (3.2.6) lib/active_record/query_cache.rb:64:in `call'
activerecord (3.2.6) lib/active_record/connection_adapters/abstract/connection_pool.rb:473:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
activesupport (3.2.6) lib/active_support/callbacks.rb:405:in `_run__60653626266012267__call__4496837804684830799__callbacks'
activesupport (3.2.6) lib/active_support/callbacks.rb:405:in `__run_callback'
activesupport (3.2.6) lib/active_support/callbacks.rb:385:in `_run_call_callbacks'
activesupport (3.2.6) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (3.2.6) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/reloader.rb:65:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/remote_ip.rb:31:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
railties (3.2.6) lib/rails/rack/logger.rb:26:in `call_app'
railties (3.2.6) lib/rails/rack/logger.rb:16:in `call'
quiet_assets (1.0.1) lib/quiet_assets.rb:20:in `call_with_quiet_assets'
actionpack (3.2.6) lib/action_dispatch/middleware/request_id.rb:22:in `call'
rack (1.4.1) lib/rack/methodoverride.rb:21:in `call'
rack (1.4.1) lib/rack/runtime.rb:17:in `call'
activesupport (3.2.6) lib/active_support/cache/strategy/local_cache.rb:72:in `call'
rack (1.4.1) lib/rack/lock.rb:15:in `call'
actionpack (3.2.6) lib/action_dispatch/middleware/static.rb:62:in `call'
airbrake (3.1.1) lib/airbrake/rack.rb:30:in `call'
airbrake (3.1.1) lib/airbrake/user_informer.rb:12:in `call'
railties (3.2.6) lib/rails/engine.rb:479:in `call'
railties (3.2.6) lib/rails/application.rb:220:in `call'
rack (1.4.1) lib/rack/content_length.rb:14:in `call'
railties (3.2.6) lib/rails/rack/log_tailer.rb:17:in `call'
thin (1.3.1) lib/thin/connection.rb:80:in `block in pre_process'
thin (1.3.1) lib/thin/connection.rb:78:in `catch'
thin (1.3.1) lib/thin/connection.rb:78:in `pre_process'
thin (1.3.1) lib/thin/connection.rb:53:in `process'
thin (1.3.1) lib/thin/connection.rb:38:in `receive_data'
eventmachine (0.12.10) lib/eventmachine.rb:256:in `run_machine'
eventmachine (0.12.10) lib/eventmachine.rb:256:in `run'
thin (1.3.1) lib/thin/backends/base.rb:61:in `start'
thin (1.3.1) lib/thin/server.rb:159:in `start'
rack (1.4.1) lib/rack/handler/thin.rb:13:in `run'
rack (1.4.1) lib/rack/server.rb:265:in `start'
railties (3.2.6) lib/rails/commands/server.rb:70:in `start'
railties (3.2.6) lib/rails/commands.rb:55:in `block in <top (required)>'
railties (3.2.6) lib/rails/commands.rb:50:in `tap'
railties (3.2.6) lib/rails/commands.rb:50:in `<top (required)>'
script/rails:6:in `require'
script/rails:6:in `<top (required)>'
-e:1:in `load'
-e:1:in `<main>'

If I go on with log in (without clicking cancel at Twitter's page), then everything works correctly as expected. Same for Facebook, I can log in just fine, but if I press 'cancel' at Facebook's page, I get redirected back and I throw a 500.

Is there a way to handle this better? I'd like to be able to show a nice page.

When there's a failure, most of the times depending on the type of failure, OmniAuth will call OmniAuth.config.on_failure which by default is set to OmniAuth::FailureEndpoint. By default it is supposed to raise an exception in development mode and redirect otherwise:

def call
  raise_out! if ENV['RACK_ENV'].to_s == 'development'
  redirect_to_failure
end

If that is not working as expected for you, then you can force the redirection to always happen, even on dev mode, by adding this to your initializer:

class SafeFailureEndpoint < OmniAuth::FailureEndpoint
  def call
    redirect_to_failure
  end
end

OmniAuth.config.on_failure = SafeFailureEndpoint

This might or might not be bug: https://github.com/intridea/omniauth/issues/616

What is Rails Way? (readability vs drying)

8 votes

I have a User model, which have voting methods. I want to write proxy methods for voting.

This is readable way:

def vote_up item
  return false unless can? :vote, item
  vote item, :up
end

def vote_down item
  return false unless can? :vote, item
  vote item, :down
end

And this is DRY way:

%w(up down).each do |vtype|
  define_method "vote_#{vtype}" do |item|
    return false unless can? :vote, item
    vote item, vtype.to_sym
  end
end

Which one is better and why?

Purely because OP seemed to like my comment, I'll put it as an answer:

Personally, considering you only have 2 methods here, and it's unlikely you'd ever add more (vote_sideways? vote_diagonally?) I would just go with the readable way. If you could potentially have many, many more though, I would go with the DRY way (because it becomes easily extendible) with a readable comment to explain to other developers (or to yourself later!).

Using god only to kill

8 votes

I serve my software using passenger. It spawns many ruby processes.

Sometimes one of these rubies becomes bloated and I want it to die.

I was hoping to use god to that intent. My idea was to monitor all these rubies and if it is consuming more than 500MB of memory for 3 cycles, god should try to gracefuly kill it. If it remains alive for more than 5 minutes then god should kill it not gracefully.

It seems to me that god always tries to run the service again, so it forces us to provide a start command. Is it possible to use god only to kill bad behaviored processes and let the passenger spawner to bring them back to live when necessary?

Answer to your question lies in question itself. you can kill ruby processes using god gem which is ruby process process monitor framework by github guys.

basically, here is how it works:

  1. configure god to monitor process it can be anything from apache,passenger,mongrel or just simple file doing a long-running task.
  2. Set conditionals in god's configuration file based upon which god will execute some predefined code.

here is a simple example(taken from docs). consider this as file long running process that runs undefiantly which we want to monitor for memory usage, lets call it simple.rb

loop do
  puts 'Hello'
  sleep 1
end

now, we install the god gem & configure it to as run as superuser so it can kill/spawn processes and next create a configuration file. example(also taken from docs):

God.watch do |w|
  w.name = "simple"
  w.start = "ruby /full/path/to/simple.rb"
  w.keepalive(:memory_max => 500.megabytes)
end

Here, as you may have got the idea if the process memory usage goes above 500 megabytes, god will restart it. here are few resources that might help, if you are getting started with process management using god gem:

Now, please remember ALL configuration for god is actually legal ruby code so you can get creative & do all sorts of things.

lastly, if you are frequently finding yourself running long running process, I advice you to try JRuby which is works much better with long running processes due to JVM & LOT faster than MRI

How to DRY scope methods used in two different classes?

5 votes

I am using Ruby on Rails 3.2.2 and I would like to retrieve / scope associated objects by "specifying" / "filtering on" an attribute value on those associated objects. That is, at this time I am using the following code:

class Article < ActiveRecord::Base
  def self.search_by_title(search)
    where('articles.title LIKE ?', "%#{search}%")
  end
end

class ArticleAssociation < ActiveRecord::Base
  def self.search_by_article_title(search)
    joins(:article).where('articles.title LIKE ?', "%#{search}%")
  end
end

In the above code the where('articles.title LIKE ?', "%#{search}%") clause is repeated twice and so I thought that it may be improved with the DRY principle: is it possible to use the Article.search_by_title method directly in the ArticleAssociation.search_by_article_title method?


Typical use cases are:

  • ArticleAssociation.search_by_article_title("Sample string")
  • Article.search_by_title("Sample string")

Unless you change the code structure completely, no.

You could do some hacking with lambdas, but that would be more code then the code you're DRYing. There is a such thing as good refactoring, and a such thing as bad refactoring. Unless a piece of very complex or long code is used in 2 or more places, then you can worry about refactoring. Code conventions are important, but for tiny one-method-call things like that its a waste and will probably make your code more cryptic.

Though, I know that it's annoying when people don't answer your question, so here:

class Article < ActiveRecord::Base
  SEARCH_BY_TITLE=lambda {|obj, search| obj.where('articles.title LIKE ?', "%#{search}%")}
  def self.search_by_title(search)
    SEARCH_BY_TITLE.call(self, search)
  end
end

class ArticleAssociation < ActiveRecord::Base
  def self.search_by_article_title(search)
    Article::SEARCH_BY_TITLE.call(joins(:article),search)
  end
end

That just makes a lambda as a constant that performs the where call on a specified object. Both methods just wrap that lambda.

Note: Although this may be considered more elegant, it will decrease performance a lot, as lambdas, closures, and the extra call are expensive in a dynamic language like Ruby. But I don't think that's an issue for you.

Rails 3.2.3 namespaced controllers being overridden by global controllers with same name

5 votes

When the global application controller is loaded first, the namespaced application controller does not load when loading pages within that namespace. The application controller looks like this:

class ApplicationController < ActionController::Base
 protect_from_forgery
end

And the namespaced application controller looks like this:

class Admin::ApplicationController < ApplicationController

def authenticate_admin!
 if current_admin.nil?
  redirect_to new_admin_session_url
 end
end

private

 def current_admin
  @current_admin ||= Admin.find(session[:admin_id]) if session[:admin_id]
 end

helper_method :current_admin
end

When we use the before_filter "authenticate_admin!" like this:

class Admin::AssetsController < Admin::ApplicationController
  before_filter :authenticate_admin!
end

A "NoMethodError in Admin::AssetsController#new" is thrown. This only occurs when we hit the global route before the namespaced route. If the server is restarted and the namespaced route is loaded first everything works properly.

This is happening because you also happen to have an Admin model (a Class) with the same name as your namespace.

This Google group thread provides a good explanation of what exactly is happening.

To fix, I would either rename the model to AdminUser or if that is not a possibility, renaming the namespace will also fix the issue.

How to preview a delete_all or destroy_all query in Rails

5 votes

You know the drill: some invalid data pops up in the production database and you have to get rid of it. You fire up your Rails console on the production server and type in the query:

Foo.where(bar: 'baz').all

You review the returned data and it's what you need to remove. Then you type:

Foo.where(bar: 'baz').destroy_all

And your heart stops for a second. You just want to see the query before it runs.

Is there any way to do that in Rails? I'm looking for a method similar to

Foo.where(bar: 'baz').to_sql

but the one that will return the DELETE query.

Just off the top of my head, you could run the console in sandbox mode and run the delete query to see the sql. The changes would just be rolled back on exit.

Why the use of both <% and <%= in the views?

5 votes

If I write something like:

<% if signed_in?.blank? %> or <%= link_to "Sign Up", sign_up_path %>

What is the difference between the two signs of <% and <%=?

Why make it this way instead of using just one for simplicity?

When do I know I need to use <% over <%=?

<%= puts the return value of the code inside to the page.

<% just execute code.

Here is the good guide about ERB http://api.rubyonrails.org/classes/ActionView/Base.html

How to encrypt data in a UTF-8 string using OpenSSL::Cipher?

5 votes

In a Rails 3.0 (Ruby 1.9.2) app I'm trying to encrypt some data using something like this:

cipher = OpenSSL::Cipher.new 'aes-256-cbc'
cipher.encrypt
cipher.key = cipher.random_key
cipher.iv = cipher.random_iv

encrypted = cipher.update 'most secret data in the world'
encrypted << cipher.final

That will go into a UTF-8 database. My problem is that

> encrypted.encoding
 => #<Encoding:ASCII-8BIT>

> encrypted.encode 'utf-8'
Encoding::UndefinedConversionError: "\xF7" from ASCII-8BIT to UTF-8

How can I get an UTF-8 encrypted string?

The solution is to convert the ASCII-8BIT string to Base64 and then encode to UTF-8.

cipher = OpenSSL::Cipher.new 'aes-256-cbc'
cipher.encrypt
cipher.key = cipher.random_key
cipher.iv = cipher.random_iv

encrypted = cipher.update 'most secret data in the world'
encrypted << cipher.final

encoded = Base64.encode64(encrypted).encode('utf-8')

Once persisted and retrieved from the database,

decoded = Base64.decode64 encoded.encode('ascii-8bit')

and finally decrypt it.


PS: If you're curious:

cipher = OpenSSL::Cipher.new 'aes-256-cbc'
cipher.decrypt
cipher.key = random_key
cipher.iv = random_iv

decrypted = cipher.update encoded
decrypted << cipher.final

> decrypted
 => 'most secret data in the world'

ActiveRecord query much slower than straight SQL?

5 votes

I've been working on optimizing my project's DB calls and I noticed a "significant" difference in performance between the two identical calls below:

connection = ActiveRecord::Base.connection()
pgresult = connection.execute(
  "SELECT SUM(my_column)
   FROM table
   WHERE id = #{id} 
   AND created_at BETWEEN '#{lower}' and '#{upper}'")

and the second version:

sum = Table.
      where(:id => id, :created_at => lower..upper).
      sum(:my_column)

The method using the first version on average takes 300ms to execute (the operation is called a couple thousand times total within it), and the method using the second version takes about 550ms. That's almost 100% decrease in speed.

I double-checked the SQL that's generated by the second version, it's identical to the first with exception for it prepending table columns with the table name.

  • Why the slow-down? Is the conversion between ActiveRecord and SQL really making the operation take almost 2x?
  • Do I need to stick to writing straight SQL (perhaps even a sproc) if I need to perform the same operation a ton of times and I don't want to hit the overhead?

Thanks!

A couple of things jump out.

Firstly, if this code is being called 2000 times and takes 250ms extra to run, that's ~0.125ms per call to convert the Arel to SQL, which isn't unrealistic.

Secondly, I'm not sure of the internals of Range in Ruby, but lower..upper may be doing calculations such as the size of the range and other things, which will be a big performance hit.

Do you see the same performance hit with the following?

sum = Table.
      where(:id => id).
      where(:created_at => "BETWEEN ? and ?", lower, upper).
      sum(:my_column)

Ruby gem for text comparison

5 votes

I am looking for a gem that can compare two strings (in this case paragraphs of text) and be able to gauge the likelihood that they are similar in content (with perhaps only a few words rearranged, changed). I believe that SO uses something similar when users submit questions.

I'd probably use something like Diff::LCS:

>> require "diff/lcs"
>> seq1 = "lorem ipsum dolor sit amet consequtor".split(" ")
>> seq2 = "lorem ipsum dolor amet sit consequtor".split(" ")
1.9.3-p194 :010 > Diff::LCS.diff(seq1, seq2).length
 => 2

It uses the longest common subsequence algorithm (the method for using LCS to get a diff is described on the wiki page).