Ruby Quicktips Logo

Ruby Quicktips

Random Ruby and Rails tips.
This blog is dedicated to deliver short, interesting and practical tidbits of the Ruby language and Ruby on Rails framework. Read more...

Your submissions are more than welcome!
Feb 4 ’11

How to check if objects or relations exist

Here’s an interesting fact when checking if objects or relations exist in a collection.
To check if there were any items present in a collection you can do something like this:

Object.relation.present?

This, however, is better:

Object.relation.any?

Turns out that - when you request associated objects for the first time - the any? method will perform a COUNT (*) SQL query where as the present? method will perform a SELECT (*) which is infinitely slower than performing a count.

blog = Blog.first
blog.posts.present?
# SQL (284.1ms) SELECT * FROM "posts" WHERE ("posts".blog_id = 1)
blog = Blog.first
blog.posts.any?
# SQL (1.2ms) SELECT count(*) AS count_all FROM "posts" WHERE ("posts".blog_id = 1)

Thanks to Mario and Keith for this tip.

47 notes 0 comments (via mariovisic-blog)

Jan 20 ’11

Benchmark.ms: Rails you sneaky devil.

I am sure that we have all had to track how long some bit of code takes to process. For auditing purposes or whatever. The typically way we do this is to save the time just before the execution of our action, perform the action, and then get the time when the action completes. End time - Start time = Elapsed time. Hurrah! Look at us being geniuses….

And now for the “bring you back to earth because we did something the not so Rails (or rather Ruby) way” moment. Rails, in it’s sneakiness has extended the Benchmark class and given us a method called #ms. This method receives a block of code and gives the elapsed time for a return result. Did you catch that? Did you really? Because I said the #ms functions return result is the elapsed time. Not the result of the block. This, if you aren’t keeping it in mind can cause a problem.

Thar be Dragons

Let’s say you want to see how long it takes to look up a person in your DB (simple but gets the point across). You might start out by doing something like this:

ms_murder = User.find(:first, :conditions => { :some => "condition" })

Then you think to yourself “I wonder how long that takes”. So you now know about the Benchmark#ms function to you just wrap your previous code like so

Benchmark.ms do
 ms_murder = User.find(:first, :conditions => { :some => "condition" })
end
#=> 0.33299827575684

Great! now you know how long it takes. But wait. What happens when you try to use your ms_murder object?

ms_murder.login
#=> NameError: undefined local variable or method `ms_murder' for #<Object:0x1001972a0>

Wah wah. The problem here should be obvious but just to clarify the variables that are defined within the Benchmark#ms block are not available outside of that. There are a few ways around this. The first is to initialize the vars before the code block, blech. The second is to use instance variables, warm and fuzzy. I’m sure there are other more creative ways but I have found this works for most of my needs:

Benchmark.ms do
 @ms_murder = User.find(:first, :conditions => { :some => "condition" })
end
#=> 0.33299827575684
@ms_murder.login
#=> "jerrol"

You can also do this if you need to keep the elapsed time around for whatever reason.

elapsed_time = Benchmark.ms do
 @ms_murder = User.find(:first, :conditions => { :some => "condition" })
end
#=> 0.33299827575684
@ms_murder.login
#=> "jerrol"
elapsed_time
#=> 0.33299827575684

9 notes 0 comments (via schmidt-happens)

Jan 11 ’11

Random choice - eh, I mean sample - of an array’s elements

Need a randomly chosen element from an array? There’s a method for that!
Array#choice (Ruby 1.8.7) or Array#sample (Ruby > 1.8.7):

[1,2,3,4,5,6,7,8,9].choice
=> 5 
[1,2,3,4,5,6,7,8,9].sample
=> 8
[1,2,3,4,5,6,7,8,9].sample(3)
=> [3,8,9]

Thanks to everyone who mentioned these methods here and here.

14 notes 0 comments

Jan 10 ’11

How to Call Private Methods On Objects

Calling private methods can for example be useful in unit testing to increase the code coverage.
Object#send gives you access to all methods of a particular object (even protected and private ones).

obj.send(:method [, args...])

In case send method has been overwritten, you can also use its aliased version __send__.

11 notes 0 comments (via rubyloveinfo)

Jan 7 ’11

attr_accessor_with_default

Here’s a method I haven’t seen before: attr_accessor_with_default

This ActiveSupport method allows you to set a default value for an attribute accessor:

class Person
 attr_accessor_with_default :age, 25
end
some_person.age # => 25
some_person.age = 26
some_person.age # => 26

You can even pass in a block.

20 notes 0 comments (via rubyflare)

Jan 6 ’11

Random Array Item

From 1.8.7 on, there is the Array#shuffle method.

[1,2,3].shuffle # => [2,1,3]

This makes it extremely easy to write Array#random to pick a random item from an array

class Array
 def random
 shuffle.first
 end
end
[1,2,3,4,5,6,7,8,9].random # => 5
[1,2,3,4,5,6,7,8,9].random # => 1
[1,2,3,4,5,6,7,8,9].random # => 3

This tip was submitted by Justin Baker.

2 notes 0 comments

Jan 6 ’11

Prevent String#split from throwing away empty trailing elements

The default behavior of String#split will throw away any trailing values if they are empty.

> "Hello,There,,".split(',') 
=> ["Hello", "There"]

If you want to keep those empty trailing elements, pass a negative number for the second (limit) parameter.

> "Hello,There,,".split(',', -1)
=> ["Hello", "There", "", ""]

This tip was submitted by two-bit-fool.

10 notes 0 comments

Dec 21 ’10

Delay your Javascript execution

There’s a Prototype helper method called delay, so you can more precisely say when something will happen.
For example, you can do stuff like this inside your RJS files:

page["old_element"].visual_effect :blind_up, :duration => 0.5
page.delay(0.5) do
 page.replace :old_element, :partial => "new_element"
 page["new_element"].visual_effect :blind_down
end

Check out the delay method.

3 notes 0 comments

Dec 14 ’10

Array#first and Array#last parameters

Did you know you can pass a number parameter to Array#first and Array#last?

x = [1,2,3,4,5,6,7,8,9,10]
x.first 5 
=> [1,2,3,4,5] 
x.last 2 
=> [9,10] 

This tip was submitted by Alfred Nagy.

29 notes 0 comments

Dec 7 ’10

42

You know you can access the 42nd element of an Array like this:

my_array[41]

In Rails, you can also access this element with the forty_two method:

my_array.forty_two

Check out the Array#forty_two method.

6 notes 0 comments

Dec 2 ’10

Big Numbers

Your number has too many zeros? In ruby you can make that more readable (and easier to write!) by using underscores:

moneys = 1_000_000.00
=> 1000000.0

7 notes 0 comments (via rubyloveinfo)

Nov 29 ’10

Spell: Dynamic Dispatch

Coming from java - from time to time it just has to be… “copy-paste-time”. You’re used to it:

puts "response.inspect: #{response.inspect}"
puts "response.error_type: #{response.error_type}"
puts "response.response: #{response.response}"
puts "response.body: #{response.body}"

But wait - this is Ruby! Let’s have some fun with that spell I read about: Dynamic Dispatching. Let’s define a method that takes the object and the method to be called:

def show_response_method(method_to_call, response)
 puts "response.#{method_to_call}: #{response.send(method_to_call)}"
end

Now, we don’t have to repeat the textual output all the time:

show_response_method :inspect, response
show_response_method :error_type, response
show_response_method :response, response
show_response_method :body, response

And, in a more Ruby-like manner, we can bum some lines by using this little fellow:

[:inspect, :error_type, :response, :body].each { |method| show_response_method method, response }

We could furthermore use the Open Class concept and get funky with a little Monkey Patching and inject this method into the response object itself - but this would be one of the cases where monkey patching is not the right thing to do. At least, this is my opinion. What do you think about it?

This tip was submitted by 5v3n.

22 notes 0 comments

Nov 29 ’10

The Beauty of Collect

Being from c programming background, to get an array of some property from the objects, I used to write this in Ruby:

amount_array = []
for order in account.orders
 amount_array << order.amount.some_operation
end

While a much cleaner way is to use Array#collect:

amount_array = account.orders.collect { |order| order.amount.some_operation }

This tip was submitted by zerothabhishek.

5 notes 0 comments

Nov 28 ’10

Use OpenStruct for application configuration variables

Every rails app I’ve ever built needs some sort of configuration, and I seem to be solving this problem a different way every time, which really bothers me. Today I learned about a new class called OpenStruct. Here’s how you could use it.

# in app_root/config/initializers/app_config.rb
require 'ostruct'
AppConfig = OpenStruct.new
AppConfig.default_email = "no-reply@example.com"
AppConfig.api_url = "staging.someapi.com"

Now you have a neat way of defining global configuration variables without using constants or defining custom classes.

This tip was submitted by Jon Druse.

10 notes 0 comments

Nov 26 ’10

Deep clone

Ruby comes with an Object#clone method that lets you copy objects. But this method makes a shallow copy, i.e. a duplicate without copying any referenced objects.

Object#clone:

Produces a shallow copy of obj - the instance variables of obj are copied, but not the objects they reference.

If you need a deep clone of an object - i.e. a copy including referenced objects - the Marshal module is your friend:

deep_cloned = Marshal::load(Marshal.dump(origin))

This tip was submitted by Jaime Iniesta.

3 notes 0 comments

[フレーム]

AltStyle によって変換されたページ (->オリジナル) /