# Rails Web Service: Convert Parameter to Class Method Call?

**URL:** <https://www.ruby-forum.com/t/rails-web-service-convert-parameter-to-class-method-call/48977>\
**Category:** Ruby\
**Created:** [November 28, 2005, 2:29am UTC](https://www.ruby-forum.com/t/rails-web-service-convert-parameter-to-class-method-call/48977 "2005-11-28T02:29:42Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![craigjordanlaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8797f3/32.png) [@craigjordanlaw](https://www.ruby-forum.com/u/craigjordanlaw)\
**Post date:** [November 28, 2005, 2:29am UTC](https://www.ruby-forum.com/t/rails-web-service-convert-parameter-to-class-method-call/48977/1 "2005-11-28T02:29:42Z")

</div>

I’m trying to write a method for a web service that will find objects  
from a user specified table, i.e. find all Widgets added in last 7  
days, or find all Whatsits whose name starts with Q.

I could right a separate method for each table calling i.e.  
Widget.find() or Whatsit.find(), but what I’d like to do is have a  
single interface that lets me call something like  
user\_specified\_table.find() where user\_specified\_table is a string  
equal to either Widget or Whatsit.

How can I do this? Is there an entirely different way of doing this  
that I should be looking at?

---

<div class="post-metadata">

**Author:** ![craigjordanlaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8797f3/32.png) [@craigjordanlaw](https://www.ruby-forum.com/u/craigjordanlaw)\
**Post date:** [November 28, 2005, 3:09am UTC](https://www.ruby-forum.com/t/rails-web-service-convert-parameter-to-class-method-call/48977/2 "2005-11-28T03:09:56Z")

</div>

Craig wrote:

> How can I do this? Is there an entirely different way of doing this  
> that I should be looking at?

method\_missing is your best friend.  
Oh, and ‘send’, too.

Fast attempt at an example:  
#!/usr/local/bin/ruby  
class Finder

def method\_missing( sym, \*args )  
if sym.to\_s =~ /(\w+)_find$/  
klass = $1.capitalize  
“#{klass}.find”  
elsif sym.to\_s =~ /(\w+)find\_by([a-z_]+)/  
klass = $1.capitalize  
params = $2  
“#{klass}.find\_by\_#{params}”  
else  
super  
end  
end  
end

if **FILE** == $0  
require ‘test/unit’  
class TC\_FOO \< Test::Unit::TestCase

```
 def setup
  @f = Finder.new
end

def test_00
  res = @f.whatsit_find
  assert_equal( "Whatsit.find" , res )
end

def test_01
  res = @f.widget_find_by_name
  assert_equal( "Widget.find_by_name" , res )
end

def test_02
  assert_raise( NoMethodError ){
  @f.widget_fetch_me_coffee
  }
end

```

end  
end

James

–

[http://www.ruby-doc.org](http://www.ruby-doc.org) - Ruby Help & Documentation  
[Ruby Code & Style](http://www.artima.com/rubycs/) - Ruby Code & Style: Writers wanted  
[http://www.rubystuff.com](http://www.rubystuff.com) - The Ruby Store for Ruby Stuff  
[http://www.jamesbritt.com](http://www.jamesbritt.com) - Playing with Better Toys  
[http://www.30secondrule.com](http://www.30secondrule.com) - Building Better Tools

---

<div class="post-metadata">

**Author:** ![craigjordanlaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8797f3/32.png) [@craigjordanlaw](https://www.ruby-forum.com/u/craigjordanlaw)\
**Post date:** [November 28, 2005, 6:15am UTC](https://www.ruby-forum.com/t/rails-web-service-convert-parameter-to-class-method-call/48977/3 "2005-11-28T06:15:16Z")

</div>

Thanks for the quick reply. I’m just starting with both Ruby and Rails,  
so this was very helpful. How would you execute the result of the  
method\_missing call? What should I do to make sure this is secure?

---

<div class="post-metadata">

**Author:** ![craigjordanlaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8797f3/32.png) [@craigjordanlaw](https://www.ruby-forum.com/u/craigjordanlaw)\
**Post date:** [December 2, 2005, 5:36am UTC](https://www.ruby-forum.com/t/rails-web-service-convert-parameter-to-class-method-call/48977/4 "2005-12-02T05:36:20Z")

</div>

This is very helpful. Thank you very much. Not only have you helped me  
with this particular problem, you’ve sent me scurrying after several  
new concepts that have me thinking about other problems in new ways.

---

<div class="post-metadata">

**Author:** ![craigjordanlaw](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8797f3/32.png) [@craigjordanlaw](https://www.ruby-forum.com/u/craigjordanlaw)\
**Post date:** [November 29, 2005, 7:43am UTC](https://www.ruby-forum.com/t/rails-web-service-convert-parameter-to-class-method-call/48977/5 "2005-11-29T07:43:28Z")

</div>

Craig wrote:

> Thanks for the quick reply. I’m just starting with both Ruby and Rails,  
> so this was very helpful. How would you execute the result of the  
> method\_missing call? What should I do to make sure this is secure?

Once method\_missing has teased apart the request, you have few options.

The example just created a string of code, so you could just pass that  
to eval(). Not recommend expect perhaps to test some code to see that  
things are perhaps working up to that point.

Since you decompose the name of the missing method into a class name and  
a request, you can get a reference to the class then try to invoke  
request as a class method.

class Finder

def method\_missing( sym, \*args )  
if sym.to\_s =~ /(\w+)_find$/  
klass = $1.capitalize  
cls = Object.const\_get( klass )  
return cls.find  
elsif sym.to\_s =~ /(\w+)find\_by([a-z_]+)/  
klass = $1.capitalize  
cls = Object.const\_get( klass )  
params = $2  
cls.send( “find\_by\_#{params}”, args )  
else  
super  
end  
end  
end

If you prefer to create object instances, then first call ‘new’ on the  
class reference:

def method\_missing( sym, \*args )  
if sym.to\_s =~ /(\w+)_find$/  
klass = $1.capitalize  
cls = Object.const\_get( klass )  
obj = cls.new  
return obj.find  
elsif sym.to\_s =~ /(\w+)find\_by([a-z_]+)/  
klass = $1.capitalize  
cls = Object.const\_get( klass )  
params = $2  
obj = cls.new  
obj.send( “find\_by\_#{params}”, args )  
else  
super  
end  
end

Note that all sorts of error handling has been omitted here.

You may want to take more precautions in what classes are created and  
what methods get invoked. For example you could first check that the  
extracted class name is contained in an ‘allowed objects’ list before  
instantiation anything.

Hope this helps,

## James B.

[http://www.ruby-doc.org](http://www.ruby-doc.org) - Ruby Help & Documentation  
[Ruby Code & Style](http://www.artima.com/rubycs/) - Ruby Code & Style: Writers wanted  
[http://www.rubystuff.com](http://www.rubystuff.com) - The Ruby Store for Ruby Stuff  
[http://www.jamesbritt.com](http://www.jamesbritt.com) - Playing with Better Toys  
[http://www.30secondrule.com](http://www.30secondrule.com) - Building Better Tools
