If you want to access an object only if it’s present, you can use Rails’ Object#presence.
The API docs on presence have a good explanation:
This is handy for any representation of objects where blank is the same as not present at all. For example, this simplifies a common check for HTTP POST/query parameters:
state = params[:state] if params[:state].present?
country = params[:country] if params[:country].present?
region = state || country || 'US'…becomes:
region = params[:state].presence || params[:country].presence || 'US'This blog now has its own domain.
http://rubyquicktips.tumblr.com is now http://rubyquicktips.com.
If you want to check if associations of an object have been eager loaded, use the loaded? method:
@blogpost = Post.includes(:comments).find(1) @blogpost.comments.loaded? => true @blogpost = Post.find(1) @blogpost.comments.loaded? => false
This might for example be useful to test eager loading in your tests.
When you load records from the database and also want to access the associated objects for each of these records, it’s a good idea to make use of eager loading. Eager loading reduces the amount of queries made to the database and therefor increases performance.
A good example is an index view where you want to display an overview of information on a particular group of objects, including their associations (for example, if you want to display a list of blogposts and for each of these posts the last - say - three comments).
To make use of eager loading, you can use the :include parameter (Rails 2) or the includes method (Rails 3) respectively when doing your ActiveRecord finds.
# Rails 2 Blogpost.all(:include => :comments) # Rails 3 Blogpost.includes(:comments).all
You can also load more than one association and nest the include statements using Arrays and Hashes:
# Rails 2
Blogpost.all(:include => [:tags, { :comments => :commenter }])
# Rails 3
Blogpost.includes(:tags, { :comments => :commenter }).allExactly one database query is performed for each model you want to load.
If you want to know more about eager loading, including why and when to use it, check out the Rails Guide on eager loading.
Ruby’s syntax allows you to spread command chains across multiple lines:
puts "You can do a lot with this in one line".reverse.sub('eno', 'elpitlum').sub(' htiw tol a', '').reverse.<< 's, too!'
…can also be written like this:
puts "You can do a lot with this in one line". reverse. sub('eno', 'elpitlum'). sub(' htiw tol a', ''). reverse. << 's, too!'
In Ruby < 1.9 you have to place the dot at the end of the line, like shown in the example above. From Ruby 1.9 on, you can also place the dot at the beginning of the next line, right before the next command call.
There are a number of different ways to run shell commands from Ruby.
Kernel#exec replaces the current process and runs the command:
exec('ls ~')
# Nothing after this command is executedThis might be a bit impractical, so have a look at the other options.
%x shortcutPlace your command inside backticks (`) or execute it within %x() and it will return the output of this command:
`ls ~` => "Applications\nDesktop\nDocuments" %x(ls ~) => "Applications\nDesktop\nDocuments"
Use Kernel#system and it will return true (command run successfully), false (unsuccessful) or nil (command execution failed):
system('ls ~')
=> trueFor all of these methods, you can access the PID and exit status of the unix process via the $? variable:
$?.pid => 11988 $?.exitstatus => 0
There are more options and I recommend these resources for more details:
Additional to the syntax for creating hashes we all know:
hash = { :first => "ruby", :second => "rails" }
# => {:first=>"ruby", :second=>"rails"}
hash[:first] # => "ruby"…Ruby > 1.9.1 adds support for another syntax:
hash = { first: "ruby", second: "rails" }
# => {:first=>"ruby", :second=>"rails"}
# you still have to access a value via a symbol
hash[:second] # => "rails"
hash[second] # NameErrorRuby’s Hash#merge lets you merge two Hashes. Duplicate entries in the merged Hash taking precedence over then ones in the calling Hash:
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 254, "c" => 300 }
h1.merge(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
h1 #=> {"a"=>100, "b"=>200}Rails’ Hash#reverse_merge takes the opposite approach when it comes to handle duplicate entries. The API docs perfectly describe what it’s good for, giving an example of a very common practise regarding a method’s options:
Allows for reverse merging two hashes where the keys in the calling hash take precedence over those in the
other_hash. This is particularly useful for initializing an option hash with default values:
def setup(options = {})
options.reverse_merge! :size => 25, :velocity => 10
endUsing
merge, the above example would look as follows:
def setup(options = {})
{ :size => 25, :velocity => 10 }.merge(options)
endThe default
:sizeand:velocityare only set if theoptionshash passed in doesn’t already have the respective key.
Both methods are also available in their Bang versions merge! and reverse_merge!.
Here are the docs: Hash#merge (Ruby) and Hash#reverse_merge (Rails).
All code examples taken from the respective API docs.
Just as you can format a string from a Time object with Time#strftime, you can also parse a string in a defined format into a DateTime or Date object, using DateTime#strptime or Date#strptime respectively (Date#strptime only creates a date without the time, though).
require 'date' parsed_time = DateTime.strptime('03/05/2010 14:25:00', '%d/%m/%Y %H:%M:%S') parsed_time.to_s => "2010年05月03日T14:25:00+00:00"
See the docs for more info: DateTime#strptime and Date#strptime.
The try method is awesome. Check the documentation.
It is usually used to call a method on an object if it exists, or return nil if it doesn’t.
But sometimes, it is not used with hashes, but this also works perfectly:
params[:search] ? params[:search][:name] : nil # Can also be written as... params[:search].try(:[],:name)
Clean!
This tip was submitted by Miguel Camba.
If you only want to print the first day of the current month you can use the string formating method on a Time object:
> Time.now.strftime("%Y-%m-1") "2011年04月1日"
The method can be used to print date in almost any format:
> Time.now.strftime("%A %B %d or %a %e/%m") => "Monday April 11 or Mon 11/04"
Check out Time#strftime for a list of directives. Time is part of the core, so there is no need to require anything.
This tip was submitted by Aqab Bin Talal.
Heredocs come in handy when you have to deal with larger multi-line strings in the source code itself. However, it usually breaks the indents:
class Poem def initialize @text = <<END "Faith" is a fine invention When Gentlemen can see But Microscopes are prudent In an Emergency. (Emily Dickinson 1830-1886) END end def recite puts @text end end
But it wouldn’t be Ruby if there were no way to make this pretty. The minus in -END makes sure any whitespace before the end marker is ignored and the first six spaces of every line are cut when the string collected by heredoc is post processed with gsub:
class Poem def initialize @text = <<-END.gsub(/^ {6}/, '') "Faith" is a fine invention When Gentlemen can see But Microscopes are prudent In an Emergency. (Emily Dickinson 1830-1886) END end def recite puts @text end end
The result for both snippets is exactly the same – provided you stick to the recommended 2 spaces indent for Ruby source code:
>> Poem.new.recite
"Faith" is a fine invention
When Gentlemen can see
But Microscopes are prudent
In an Emergency.
(Emily Dickinson 1830-1886)This tip was submitted by Sven Schwyn and originally posted on his blog.
In Rails 2 the only way to add multiple validations to a field is through separate validate statements:
validates_presence_of :title validates_length_of :title, :maximum => 30
Rails 3 simplifies this process by adding a method called validates which is a “shortcut to all default validators”. Using the validates method your code will look like this:
validates(:title, :presence => true, :length => {:maximum => 30})You can find more information about this method in the API documentation here.
You can define the “number” ‘infinity’ (or ’-infinity’) in Ruby like this:
1.0/0 => Infinity -1.0/0 => -Infinity
Infinity and -Infinity behave just like you expect them to: they are always bigger - or always smaller, respectively - than any number you compare it to.
The Xing Devblog had a great post recently about using Ruby’s infinity in Rails, with some thoughts on when you might want to use it (or not).
P.S.: the Float class in Ruby 1.9.2 provides an Infinity constant you can use:
Float::INFINITY => Infinity
This tip was submitted by makoto.
Because Object.methods returns an array, you can grep that just like in this tip about grepping anything from your enumerables.
For example, if you are looking for a particular method of an object, you can easily narrow down the results like this:
Object.methods.grep /inspect/ => ["inspect", "pretty_inspect", "pretty_print_inspect"]
This tip was submitted Adam Rogers.