6: Shortcut Blocks with Symbol to_proc
(view original Railscast)
The odd syntax in the find line in the code block below, with the ampersand and symbol, is called Symbol to_proc and is something that Rails adds to Ruby.
class Project < ActiveRecord::Base has_many :tasks def self.all_names find(:all).collect(&:name) end end
We’ll use Rails’ script/console
to explain how it works. First, let’s get an array of Project
s
Laa-Laa:todo eifion$ script/console
Loading development environment (Rails 2.2.2)
>> projects = Project.find(:all)
=> [#<Project id: 1, name: "Write another ASCIIcast", created_at: "2008-12-29 09:32:47", updated_at: "2008-12-29 09:32:47">, #<Project id: 2, name: "Go out walking", created_at: "2008-12-29 09:33:04", updated_at: "2008-12-29 09:33:04">]
There are two projects and we want to return an array of all of the project names. One way to do that would be to use the collect
method, which takes a block, and return the name
of each Project
. The collect
method iterates through an array, executes some code against each item in the array, and returns an array containing each result of the code executed against each item in the original array.
>> projects.collect { |p| p.name }
=> ["Write another ASCIIcast", "Go out walking"]
Symbol to_proc allows you to use a shortcut when you want to perform a method call against the object that is sent to the block. To do this you pass a parameter that starts with an ampersand followed by the name of the method as a symbol:
>> projects.collect {&:name}
=> ["Write another ASCIIcast", "Go out walking"]
This becomes more useful when you want to combine multiple method calls:
>> projects.collect(&:name).collect(&:upcase)
=> ["WRITE ANOTHER ASCIICAST", "GO OUT WALKING"]
This technique isn’t restricted to the collect
method; it can be applied to any method that takes a block. For example the any?
and all?
methods can use this shortcut to see if all or any of out projects are valid, or even to save all of our projects.
>> projects.all?(&:valid?)
=> true
>> projects.any?(&:valid?)
=> true
>> projects.each(&:save!)
=> [#<Project id: 1, name: "Write another ASCIIcast", created_at: "2008-12-29 09:32:47", updated_at: "2008-12-29 09:32:47">, #<Project id: 2, name: "Go out walking", created_at: "2008-12-29 09:33:04", updated_at: "2008-12-29 09:33:04">]
Despite its slightly odd syntax, Symbol to_proc is well worth using when you have to string methods together with blocks.