What is the Rails equivalent of Dependency Injection?

Coming from a Java background I’m trying to get used to the various
best practices of doing things in Rails. I’m used to Dependency
Injection and XML in the Java world.

I realize Ruby does not have interfaces and Rails avoids the use of
XML. So how does one solve certain problems that were once solved by
DI and XML? Example, if you have a shopping cart that uses Active
Merchant which comes with all sorts of payment gateways. How would
the user of the shopping cart specify the gateway they wanted? I’m
thinking there are some interesting possibilities with Ruby’s dynamic
typing. Like maybe a YAML config file listing the gateway you are
using (with other options not chose commented out)?

Does anyone have any thoughts on how this sort of problem is best
addressed in Rails?

Sean

Maybe this will help:

http://onestepback.org/articles/depinj/index.html

schof wrote:

Coming from a Java background I’m trying to get used to the various
best practices of doing things in Rails. I’m used to Dependency
Injection and XML in the Java world.

I realize Ruby does not have interfaces and Rails avoids the use of
XML. So how does one solve certain problems that were once solved by
DI and XML? Example, if you have a shopping cart that uses Active
Merchant which comes with all sorts of payment gateways. How would
the user of the shopping cart specify the gateway they wanted? I’m
thinking there are some interesting possibilities with Ruby’s dynamic
typing. Like maybe a YAML config file listing the gateway you are
using (with other options not chose commented out)?

Does anyone have any thoughts on how this sort of problem is best
addressed in Rails?

I’ve never given it a whirl from within Rails, but Needle [1] is
probably be able to handle this.

[1] http://needle.rubyforge.org/


Roderick van Domburg

On 7/29/07, Roderick van Domburg [email protected]
wrote:

[1] http://needle.rubyforge.org/

Before you go look at Needle, or any other “dependency injection”
framework for Ruby, it’s worth seeing what Jamis B. (original author
of Needle) has to say now about it now[1].

In Java, DI was all about not caring what the actual implementation
class was. In Ruby, however, we don’t need to worry about that … a
class either responds to a method call or it doesn’t. In Ruby, why
should you bother to care what the underlying type is? Or, care about
whether or not it already has predefined methods for all your config
parameters? Or, whether the class actually has any notion of
“properties” at all?

Imagine what “routes.rb” would look like if we had to do it in Java …

Craig

[1] Buckblog: Net::SSH revisited

schof wrote:

Does anyone have any thoughts on how this sort of problem is best
addressed in Rails?

Sean

Change your line of thinking to: “Why was DI needed for full stack
containers written with statically binded languages?”

Because due to the fact that the only way to incorporate cross cutting
concerns into those containers that were written with statically binded
languages was to either:

  • Modify the byte code directly: (AspectJ, JBoss)
  • Register callbacks directly at defined points within the container via
    constructor/setter/interface injection. (Spring, Pico, etc… )
  • Incorporate meta-level “aspects” into the code itself (EJB3.0,
    Hibernate 3, etc…)

With Ruby, there is simply no need to this as either the container
and/or the 3rd party component can open of the entity it wants to modify
itself and “inject, modify, or remove” operations as required!

In fact, this concept is a core to the Ruby language itself. If you
look at attr_reader, it’s actually a method that “injects” code within
your class as it’s being parsed by the Ruby runtime! (It’s not a keyword
as many people with a Java background believe)

In summary, Ruby’s dynamic binding doesn’t suffer from the crutch of
statically binded languages and therefore doesn’t need DI. IMHO is one
of the major reasons why Rails is so successful in the first place.

hth

ilan

It’s also worth noting that Jamis is on the Rails Core team, and they
don’t use needle. I remember reading DHH saying that he (they?)
considered using Needle, but didn’t end up needing it. Anyone
remember where that was?

Forrest

Schof -

On 30-Jul-07, at 12:07 PM, Ilan B. wrote:

containers written with statically binded languages?"
Hibernate 3, etc…)
as many people with a Java background believe)

In summary, Ruby’s dynamic binding doesn’t suffer from the crutch of
statically binded languages and therefore doesn’t need DI. IMHO is
one
of the major reasons why Rails is so successful in the first place.

hth

ilan

I know this isn’t the answer to your question, but Jamis, who wrote
needle, just posted some thought on on DI while re-writing another
lib (net::ssh).

http://weblog.jamisbuck.org/2007/7/29/net-ssh-revisited

cheers,
Jodi

In Java, DI was all about not caring what the actual implementation
class was. In Ruby, however, we don’t need to worry about that … a
class either responds to a method call or it doesn’t. In Ruby, why
should you bother to care what the underlying type is? Or, care about
whether or not it already has predefined methods for all your config
parameters? Or, whether the class actually has any notion of
“properties” at all?

I realize that we don’t really need true DI anymore in Rails. Lets go
back to my scenario where you want to plug in one of many possible
payment gateways from Active Merchant. What is the best way to
configure my Rails app so another developer can easily substitute in
the gateway of their choice? I understand that it only matters that
the object have the right methods but how do you pick the object?

The most obvious solution is to just change the code but surely there
is a better way to do this? Instead of searching and replacing how
does one configure something like this in Rails?

Craig

Sean

What is the best way to
configure my Rails app so another developer can easily substitute in
the gateway of their choice?
http://softiesonrails.com/2007/3/13/ruby-101-for-net-developers-use-blocks-to-help-you-refactor

apologies if this has already been posted to this thread, but this post
is an interesting insight from the author of Needle - one of the main
ruby DI libraries

http://weblog.jamisbuck.org/2007/7/29/net-ssh-revisited

Hey Sean, if the type of gateway is to be selected from UI, then you’ll
can
use Factory Method design pattern to create the appropriate instance
based
on user’s selection. Another possibility would be to use a pluggable
adapter or Adapter design pattern. Thus, you should be able to do the
following:
a) create a common interface (i.e. GateWay) for all your gateways and
subclass it to create new gateways.

b) each subclass of GateWay would be an adpater for communicating to
the
underlying gateway.

c) create a factory method for creating the appropriate gateway based
on
developer or user
selection.

d) create the appropriate gateway instance

 gateway_a = GateWayFactory.create(  "A" )  # create gateway A

 gateway_b = GateWayFactory.create(  "B" )  # create gateway B

Good luck,

-Conrad

Usually in Ruby & Rails there’s an application-specific configuration
file (not XML, but Ruby).
A little improvisation:

config.rb

ACTIVE_MERCHANT_GATEWAYS = [ SomeKindOfGateway,
SomeOtherKindOfGateway ]

view, Settings page or something

I don’t remember, but something like this:

select_tag :current_gateway,
options_for_select(ACTIVE_MERCHANT_GATEWAYS.map do |gw| [gw.name,
gw.name] end

controller,

def set_current_gateway
gateway = params[:current_gateway].constantize # this variable HOLDS
THE CLASS ITSELF
GatewayBase.current = gateway
end

This is really untested and I don’t think I would implement it this
way (I don’t have enough information to decide that), but let me
explain:

  • Classes are just objects. You can store them in an Array.
  • Their references are not necessarily the class name. They are just
    constant (they are capitalized).
    • That’s why if you do CurrentGateway.name, you get
      “SomeKindOfGateway” for example.
  • Think of “Constantize” as Class.forName() (BUT IT’S NOT, Java
    doesn’t have real reflection). The name is confusing (at first I
    thought it was yet another inflection, just as e.g. :dasherize).
  • So, what I do is have a central configuration Ruby file (as per
    convention). Being Ruby, you can reference objects (not only its
    name). Loading the array with the classes themselves (instead of ,
    say, their names, is useful because you get an error on initialization
    if it can’t find it).
    • That array is accesible anywhere in the application (though I
      wouldn’t reference that global from a view).
  • When you say SomeClass.new, you are sending the message :new (not
    an operator, but just another message, just like an_array.length).
    SomeClass can reference any class you like, not only a “SomeClass”
    class. It’s a constant. You could have used a variable…
    • If you have any central class (a Base class for all your gateways
      or something like that), make that know which is the current gateway
      (I’ve called it GatewayBase, with its :current= method).

I’m sorry if I’m being confusing. I think the most important thing I
want to say is that a class reference is not coupled with a specific
implementation, it’s just another constant, so it can reference to any
other. Normally we configure it statically, so we could use a Constant
name for holding the class (and then any Constant.new would do). But
if, instead of GatewayBase.current you used e.g. CurrentGateway you
could only set it once at startup (and you want that to be changes in
runtime).

Bye,

nachokb