Rails hates my recursive function

I’m trying to create a function that will take input in the form
“a12345678”
and output text in the form “a12-34-5678” if and only if the input text
is *
not* in the form “adam smith” The goal is to allow my users to enter
either
names separated by a space, or the student id number into a single
search
field and have the results be returned based on the format of the query.

I came up with the following code in my student model

def self.insert_dashes(term)
if /^([A-Z]|[a-z]|\d|-){11}$/.match(term)
term.insert 3, ‘-’
term.insert 6,’-’
end
end
def self.find_record(rec)
if /^([A-Z]|[a-z]|\d|-){11}$/.match(rec)
student=Student.where(:studentID=>rec).all
elsif /^([A-Z\s]|[a-z\s])+$/.match(rec)
split=rec.split ’ ',2
f_name=split.first
l_name=split.second
student=Student.where(:fname=>f_name,:lname=>l_name).all
else
bar=insert_dashes(rec)
find_record(bar)
end
end

If I try to enter a string of the for “a12345678” I am greeted with the
following error:

SystemStackError (stack level too deep):
app/controllers/students_controller.rb:19:in `find_student’

Rendered
c:/jruby-1.6.1/lib/ruby/gems/1.8/gems/actionpack-3.0.7/lib/action_dispatch/middleware/templates/rescues/_trace.erb
(18.0ms)
Rendered
c:/jruby-1.6.1/lib/ruby/gems/1.8/gems/actionpack-3.0.7/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(41.0ms)
Rendered
c:/jruby-1.6.1/lib/ruby/gems/1.8/gems/actionpack-3.0.7/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
within rescues/layout (85.0ms)

Can anyone explain what the problem might be or a better approach to
accomplishing this particular task?

On 24 May 2011 21:31, Kevin [email protected] wrote:

def self.insert_dashes(term)
f_name=split.first
If I try to enter a string of the for “a12345678” I am greeted with the
following error:

SystemStackError (stack level too deep):
app/controllers/students_controller.rb:19:in `find_student’

Have a look at the Rails Guide on Debugging to find how to use
ruby-debug to break into your code and inspect variables and follow
flow. Then you can debug the method yourself to find what is going
wrong. That way you will learn a lot for the future.

Colin

Just put ‘puts rec’ just after the ‘def self.find_record(rec)’ and see
what you get.

On May 24, 4:31pm, Kevin [email protected] wrote:

term.insert 3, ‘-’
student=Student.where(:fname=>f_name,:lname=>l_name).all
else
bar=insert_dashes(rec)
find_record(bar)
end
end

Can anyone explain what the problem might be or a better approach to
accomplishing this particular task?

I’m wondering if there’s not some whitespace getting added on to the
search term - unless you’re stripping it elsewhere, trailing
whitespace will cause this method to run indefinitely - the first time
around insert_dashes will return nil (since it doesn’t match the
exact character count and the match is fixed at both ends), and that
will then just keep going around.

DRY is nice and all, but here I think you’re trading readability (not
to mention halting!) for one repeated line of code. Given that you
know what format the argument will be in after calling
insert_dashes, wouldn’t it make more sense to just repeat
‘Student.where(:studentID=>rec).all’ there?

Couple unrelated things:

  • I’m not sure why you’re alternating amongst different character
    classes - this is exactly identical to adding the alternatives to
    the character class. So:

/^([A-Z]|[a-z]|\d|-){11}$/

can be shortened to:

/^[A-Za-z\d-]{11}$/

and similarly for the other pattern.

  • the code as written will die with StackLevelTooDeep when a user puts
    in a name with punctuation (an apostrophe or a hyphen, for instance).
    This is most likely a bug.

  • the name of this function isn’t quite right - you’re returning an
    array from a function named find_record (singular). It would
    probably work better to use .first instead of .all in the code above,
    or to rename the function to find_records.

Hope this helps!

–Matt J.

All in all I think you are over thinking this, how about

def find_record(rec)
if rec =~ /^[a-z]\d{2}-\d{2}-\d{4}$/i
return Student.where(:studentID => rec).all
elsif rec =~ /^[a-z]\d{8}$/i
new_rec = rec.insert(5,’-’).insert(3,’-’)
return Student.where(:studentID => new_rec).all
else
f_name, l_name = rec.split(/\s+/, 2)
return Student.where(:fname => f_name, :lname => l_name).all
end
end

The first match will match the pattern “a12-34-5678” and get the
records based on that as the studentID key.

The second match matches “a12345678” which is converts into the
correct format and does the same.

The final part assumes that if the input string does not match either
pattern then is should be a name in the format “john smith” (that is
to say a string with some whitespace in it) and will get all the
student records based on that.

To be honest you should check that last assumption incase someone
inputs “john”, “dr john alan” or “john williams III”.

Unit tests is your friend here :slight_smile:

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs