refactor code in api::controller

In my api::controller i have few methods which follow the same type of structure . like :-

def index

render json:{:status => false, :message => ‘qw’} if params[:type].nil?

@stats = ChildStat.get_child_stat(@child_profile.id,@profile.id,params[:type])

render json:{:status => false, :message => ‘Child stats not found’} if @stats.empty?

end

def child_vaccines

render json:{:status => false, :message => "Please specify type: weekly, monthly in parameters "} if params[:type].nil?

@vaccines = ChildStat.get_child_vaccine(@child_profile.id,@parent_profile.id,params[:type])

render json:{:status => false, :message => "Child Vaccines not found "} if @vaccines.empty?

end

def child_meals

render json:{:status => false, :message => "Please specify type: weekly, monthly in parameters "} if params[:type].nil?

@meals = ChildStat.get_child_meals(@child_profile.id,@profile.id,params[:type])

render json:{:status => false, :message => "Child meals not found "} if @meals.empty?

end

So the above three methods follow the same structure . I am thinking to refactor or else write them in more compact form . I needs your help or suggestion for this .

thanks.

In my api::controller i have few methods which follow the same type of structure .

...

I am thinking to refactor or else write them in more compact form . I needs your help or suggestion for this .

If they're really that few and that short, I wouldn't bother. But assuming they're really more numerous or much longer, and to show the general principle, here's how you would do that:

First, notice exactly what changes about them, versus what stays the same. The first line of each is almost identical; the only variation is the message (more on that later). The second line varies in what var is set, what method is called on ChildStat, and that in the first case, that method takes two parameters, while the others take three, inserting the second. There's also that that second parameter is different between the two. The third line varies in the message rendered if the var set in the second line is empty (and of course what var that is).

So, substituting VAR#, where # is an increasing number, for each thing that varies, we have:

  render json:{:status => false, :message => VAR1} if params[:type].nil?   @VAR2 = ChildStat.VAR3(VAR4)   render json:{:status => false, :message => 'VAR5'} if @VAR2.empty?

"Wait a second, VAR4 is just one thing, and those methods each took multiple arguments!", I hear some of you say. That's right... but you can substitute an array for a sequence of things. To demonstrate, let's define a method that simply adds two numbers:

def add(a, b)   a + b end

add(1, 2) # => 3

So far so good, just basic Ruby method definition and calling. But now let's try calling it with an array:

arr = [1, 2] add(arr) # => ArgumentError: wrong number of arguments (1 for 2)

Oops! What happened? We're passing it one thing. We need to find a way to tell it to split this thing apart into its subpart. The * character does exactly that, using the array just as if you had literally typed its elements:

add(*arr) # => 3

And yes, if arr has the wrong number of things in it, add will complain again.

arr = [1] add(*arr) # => ArgumentError: wrong number of arguments (1 for 2) arr = [1, 2, 3] add(*arr) # => ArgumentError: wrong number of arguments (3 for 2)

The next most obvious shocker is VAR3. "Why, surely we can't just pass something in and tack it onto an object, expecting it to turn into a method call!"

Well, no. But we can do something very close: send it a message. "What, you want to set up some kind of interprocess communication system, create a process, or at least a thread (and we all know how well standard Ruby threads!), and send it a message? That sounds like horrible overkill!"

Yes, you're right, that would be. But that's not what I mean. Cast your memory back to the 1960s, when Alan Kay was inventing Object Orientation. He thought of an OO system as composed of objects "sending messages" to each others. Indeed, many OO languages (and programmers) speak of "sending messages" when others would say "calling methods". So what I mean is to give it some kind of "thing" that says what to do. So how do we do that in Ruby?

Enter send. These methods take a symbol, look up the method on their object whose name is the symbol, and call that method, feeding it the rest of their arguments. Suppose we have this class:

  class Foo     def foo       puts 'foo'     end     def bar(howmany)       puts 'bar' * howmany     end   private     def baz(rows,cols)       rows.times do         puts 'baz' * cols       end     end   end

Then we can make a Foo (by doing f = Foo.new), and send f symbols:

  > f.send :foo   foo   > f.send :bar   ArgumentError: wrong number of arguments (0 for 1)   > f.send :bar, 3   barbarbar   > f.send :baz, 3, 4   bazbazbazbaz   bazbazbazbaz   bazbazbazbaz

Also worth of attention is its pickier but lesser-known brother, public_send, which is much safer to use in most circumstances. This one will only call *public* methods.

  > f.public_send :foo   foo   > f.public_send :bar   ArgumentError: wrong number of arguments (0 for 1)   > f.public_send :bar, 3   barbarbar   > f.public_send :baz, 3, 4   NoMethodError: private method `baz' called for #<Foo:0x007f9d4c886260>

The main remaining challenge is the @-var, VAR2. We could probably hand the method some var to use, but frankly I don't think it would be worth the bother. The important thing is that when we're all done with our method call and whatever else we do with it, the right @-var is set to the right value. So make it the return from our master consolidated method, and assign it to the var you need, using an ordinary temp var inside.

So, we have in the end:

def check_child_stats(nil_msg, method_symbol, method_args, empty_msg)   render json:{:status => false, :message => nil_msg} if params[:type].nil?   results = ChildStat.send(method, *method_args)   render json:{:status => false, :message => empty_msg} if results.empty?   results end

  def index     @stats = check_child_stats('qw', :get_child_stat,         [@child_profile.id, @profile.id,params[:type]],        'Child stats not found')   end

  def child_vaccines     @vaccines = check_child_stats("Please specify type: weekly, monthly in parameters ",         :get_child_vaccine, [@child_profile.id,@parent_profile.id, params[:type]],         'Child Vaccines not found')   end

  def child_meals     @meals = check_child_stats("Please specify type: weekly, monthly in parameters ",         :get_child_meals, [@child_profile.id,@profile.id, params[:type]],         'Child meals not found')   end

Was that the sort of thing you were looking for?

If you find that many positional arguments hard to keep straight, you can even name them (using Ruby 2+), or make them hash options.

Lastly, two of them have a message that is the same. You could make them reference the same string, stored in the controller or some other appropriate class.