10

If I have an association name as a string, is there a way I can get a handle on the association object?

For example:

o = Order.first

o.customer will give me the customer object that this order belongs to.

If I have:

o = Order.first
relationship = 'customer'

i would like to do something like:

customer = eval("o.#{relationship}")

I know eval is a terrible option and I should avoid it. What is the best way to do this (as eval does not work in this example).

I did have this working:

customer = o.association(relationship)

I later found out that the association is not part of the public API and should not be used. Because when I took a line of code I had higher up the page off (that referenced that relationship) it stopped working.

Any ideas would be awesome!

Sean
  • 1,078
  • 14
  • 25

3 Answers3

20

What about just doing this?

customer = o.send(relationship)
mario
  • 1,248
  • 9
  • 9
  • 3
    The call to #to_sym isn't needed; send can handle strings. – Mori Jul 02 '13 at 18:10
  • Wow, like magic! Is send a rails or ruby method? I couldn't find documentation on it. Incidentally, i've never used it so i have no idea how this is working. Thanks again! – Sean Jul 02 '13 at 18:13
  • Send is a ruby method. It can also take arguments. You can find the documentation on #send here: http://ruby-doc.org/core-2.0/Object.html#method-i-send – mario Jul 02 '13 at 18:15
  • Your answer was so quick it wont even let me accept it yet, I will in a few min, thanks! – Sean Jul 02 '13 at 18:15
5

For those who fears using send:

o.association(relationship).scope
lulalala
  • 17,572
  • 15
  • 110
  • 169
3

You can use try() which will allow you manage any undefined method errors if the relationship doesn't exist.

relationship = 'customer'
foo = 'foo'

customer = o.try(relationship)
# > [
#     [0] #<Customer...

customer = o.try(foo)
# > nil

vs send():

customer = o.send(relationship)
# > [
#     [0] #<Customer... 

customer = o.send(foo)
# > NoMethodError: undefined method `foo' for #<Order...
Eric Norcross
  • 4,177
  • 4
  • 28
  • 53