Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this Rails Engine code mean: config.to_prepare &method(:activate).to_proc

I'm working with Spree, which uses Rails engines extensively. A common pattern I find is this. However I have trouble understanding this code.

class Engine < Rails::Engine 
  def self.activate
    ...
  end     

  config.to_prepare &method(:activate).to_proc
end
  1. What does .to_prepare do
  2. What does the &method operator do?
  3. What is the overall effect of the code?

Many Thanks!

like image 375
Jack Kinsella Avatar asked Feb 24 '11 11:02

Jack Kinsella


People also ask

What is a Rails engine?

1 What are Engines? Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the Rails::Application class inheriting a lot of its behavior from Rails::Engine .

What are Rails configuration?

In general, the work of configuring Rails means configuring the components of Rails, as well as configuring Rails itself. The configuration file config/application. rb and environment-specific configuration files (such as config/environments/production.

What is Mount in Rails routes?

Mount within the Rails routes does the equivalent of a Unix mount . It actually tells the app that another application (usually a Rack application) exists on that location. It is used mostly for Rails Engines.


1 Answers

&method(:activate).to_proc

This is best consumed one item at a time. (It should be noted that this portion of the code is 100% non-Rails-specific Ruby.)

method is a Ruby method (it's all very meta). It is documented thusly:

Looks up the named method as a receiver in obj, returning a Method object (or raising NameError). The Method object acts as a closure in obj’s object instance, so instance variables and the value of self remain available.

Check out the following IRB session:

ruby-1.9.2-p136 :001 > def my_method
ruby-1.9.2-p136 :002?>   puts "in my_method"
ruby-1.9.2-p136 :003?>   10
ruby-1.9.2-p136 :004?>   end
 => nil 
ruby-1.9.2-p136 :005 > method(:my_method)
 => #<Method: Object#my_method>

So the method call is looking up (in your example) the activate method and creating a Method object for it. Method contains a method called to_proc, which "returns a Proc object corresponding to this method". Continuing our IRB session:

ruby-1.9.2-p136 :006 > method(:my_method).to_proc
 => #<Proc:0x000001010a3e38 (lambda)>

Finally, we use the ampersand operator, which, when preceding a Proc object during a method call, will be replaced by the block the Proc contains. One more time in IRB:

ruby-1.9.2-p136 :007 > def executor(&block)
ruby-1.9.2-p136 :008?>   block.call
ruby-1.9.2-p136 :009?>   end
 => nil 
ruby-1.9.2-p136 :010 > executor( &method(:my_method).to_proc )
in my_method
 => 10

So, in pseudocode, what the line you listed is saying is:

config.to_prepare(a block containing the functionality of the method activate)

config.to_prepare

[Edited based on schof's comment]

config.to_prepare takes a block that should be run to set up your Railtie/Engine. It is run once in production mode and on every request in development, and is the only code guaranteed to be called on every single request in development mode. This is important if you are modifying classes (class_eval, etc.) as part of your engine initialization; otherwise, you're going to see different behavior in development vs. production.

But Why?

The reason this is a common idiom is so that you don't have to define your preparation code inside the to_prepare block itself; you can define method(s) in your class and then convert them to a block (which remembers its scope) using the magic described above. The code is functionally equivalent to:

class Engine < Rails::Engine 
  config.to_prepare do
    (the contents of self.activate)
  end
end
like image 54
Michelle Tilley Avatar answered Sep 29 '22 09:09

Michelle Tilley