13

in all the tutorials for RoR I see instances where the coder chose to use Proc.new when seemingly it is both unnecessary and rather unattractive.

Example, here is a callback for placed in a model, one using Proc.new the other presumably doing the same thing:

class Order < ActiveRecord::Base  
  before_save :normalize_card_number,  
    :if => Proc.new { |order| order.paid_with_card? }  
end

class Order < ActiveRecord::Base
  before_save :normalize_card_number, :if => "paid_with_card?"
end

So what's the difference? Why use the Proc? Don't they both call the "paid_with_card?" method?

Thanks in advance

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
MusikAnimal
  • 2,286
  • 2
  • 22
  • 28

2 Answers2

16

In the example above, using a symbol for the conditional method would probably be the best choice.

class Order < ActiveRecord::Base
  before_save :normalize_card_number, :if => :paid_with_card?
end

The string option uses eval to evaluate the Ruby code in the string. So personally, I would prefer to use a symbol if calling a method or a Proc if writing a short inline condition.

Per the RailsGuides documentation:

Using a Proc object gives you the ability to write an inline condition instead of a separate method. This option is best suited for one-liners.

I think using a Proc might be better illustrated this way:

class Order < ActiveRecord::Base
  before_save :normalize_card_number,
    :if => Proc.new { |order| order.payment_type == "card" }
end

This would possibly eliminate the need for the paid_with_card? method.

Jordan Owens
  • 692
  • 4
  • 10
  • Yep, it might be preferred to not litter rails models with methods like paid_with_card? – sunkencity Dec 28 '11 at 20:46
  • I think the :if thing suggests that there's a whole slew of configuration options that's automatically included and reused from another context. There's a default way to handle :if => string, proc, etc to config options like that and probably :unless works too. – sunkencity Dec 28 '11 at 20:47
2

I'd say it was the case that in older versions of Rails that's how we used to do things, and someone added the feature whereby you could pass a string to be evaluated as an instance method on the current model.

In simple scenarios it makes the older style redundant, but allows for the use of a Proc for more complex 'if' statements which would be impossible to achieve using a method on only the current instance.

stef
  • 14,172
  • 2
  • 48
  • 70