2

So say I have a Question model and an Answer model and Question has_many Answers (it's a multiple choice question).

Suppose that questions is a collection of Question objects.

In order to collect all the answers I can do this:

questions.collect(&:answers)

Two questions:

  1. What precisely does this syntax mean? Does it expand to

    questions.collect { |q| q.answers } 
    

    or is there something else going on here?

  2. Is there a way to do

    questions.collect { |q| q.answers.shuffle } 
    

    using the same syntax?

    collect(&:answers.shuffle) 
    

    isn't doing it.

I can't seem to find this in tutorials on ruby blocks on the web and searching for it doesn't work (search engines ignore "&:"). I found it in some inherited code.

Thanks

Uri Agassi
  • 36,848
  • 14
  • 76
  • 93
Brian
  • 21
  • 2
  • Did you try searching Stack Overflow using `[ruby] ampersand`? – Andrew Grimm Feb 09 '11 at 07:23
  • 1
    Ha! You're right. This is now one of several dupes :) http://stackoverflow.com/questions/1961030/ruby-ruby-on-rails-ampersand-colon-shortcut – Brian Feb 09 '11 at 07:31
  • possible duplicate of [What does map(&:name) mean in Ruby?](http://stackoverflow.com/questions/1217088/what-does-mapname-mean-in-ruby) – Jimmy Feb 09 '11 at 07:59
  • Not all search engines ignore special characters: http://symbolhound.com/?q=%26%3A+ruby – Gerry Jul 31 '13 at 17:17

2 Answers2

0

You can choose between either

questions.collect { |q| q.answers.shuffle }

and the one from @tokland. Your code will give you and other developers code readability and toklands solution will give you easy access. If you are going to use this pattern too often then override the to_proc method. Else use the hard way and don't play with nature.

waqar mirza
  • 555
  • 2
  • 15
0

Yes, the first question is N-duplicated, but regarding the second: no, you cannot chain methods. However, nothing stops you -other than writing code that may puzzle people- to create your own tool:

class Symbol
  def to_proc
    proc do |obj| 
      self.to_s.split(/\./).inject(obj, :send)
    end
  end
end

p ["1", "2", "3"].map(&:"to_i.succ")
# [2, 3, 4]

You can even find ways to send arguments, though it won't probably be very beautiful.

tokland
  • 66,169
  • 13
  • 144
  • 170