Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use Proc.new to call a method in a Rails callback?

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

like image 494
MusikAnimal Avatar asked Mar 01 '11 22:03

MusikAnimal


People also ask

What is Proc new in Rails?

A Proc object is an encapsulation of a block of code, which can be stored in a local variable, passed to a method or another Proc, and can be called. Proc is an essential concept in Ruby and a core of its functional programming features. square = Proc. new {|x| x**2 } square.

What are callbacks in rails?

Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.


2 Answers

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.

like image 146
Jordan Owens Avatar answered Sep 29 '22 11:09

Jordan Owens


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.

like image 20
stef Avatar answered Sep 29 '22 11:09

stef