Penalties of using an eval on every request


#1

Hello RoR!

I’m building a rails app for hosting multi-page surveys. I set up
questionnaire, question, and question_component models. Now I’m
initializing them with some data.

survey.rb
q1 = Question.new “q1”
q1.quote “Welcome to a test of the new interviewing system.”

q2 = Question.new “q2”
q2.quote “Do you like pie?”
q2.single 1 => “Yes”, 2 => “No”
q2.validation_block = Proc.new { [1,2].include?
@interview.answers[“2”] }

questionnaire.questions.concat [q1, q2]

– Real-life questionnaires can be thousands of questions long!

How horrible would it be if I initialized the questionnaire.questions
object, on each request, by reading survey.rb from disk and evaling it?

Thanks for your time!

  • Mike

#2

“Michael” == Michael J. removed_email_address@domain.invalid writes:

– Real-life questionnaires can be thousands of questions long!

How horrible would it be if I initialized the questionnaire.questions
object, on each request, by reading survey.rb from disk and evaling it?

Really horrible. Why don’t you store the populated questions in the
database?

	     Calle D. <removed_email_address@domain.invalid>
	 http://www.livejournal.com/users/cdybedahl/
"Ah, optimism. I remember optimism." -- Anya, Buffy the Vampire 

Slayer


#3

Calle D. wrote:

“Michael” == Michael J. removed_email_address@domain.invalid writes:

– Real-life questionnaires can be thousands of questions long!

How horrible would it be if I initialized the questionnaire.questions
object, on each request, by reading survey.rb from disk and evaling it?

Really horrible. Why don’t you store the populated questions in the
database?

       Calle D. <removed_email_address@domain.invalid>
   http://www.livejournal.com/users/cdybedahl/
"Ah, optimism. I remember optimism." -- Anya, Buffy the Vampire 

Slayer

That’s a good question: why not initialize it once and then store the
populated questions in the database?

That’s what I was doing, and it worked just fine, until I added
procedures (proc/lambda) for validation and branching code. Procs seem
really useful under the problem at hand, but they make the questions
unserializable.

Here’s an example of some of the procs I use:

q2.validation_block = Proc.new { [1,2].include?
@interview.answers[“q2”] }

q2.after_block = Proc.new do
if @interview.answers[“q2”] == 1
@interview.skip “q3”
else
@interview.skip “q4”
end
end

So in the controller it lets me do things like this:

if current_question.validates?
current_question.after_block.call
render …next question…
else
render …same question…
end

I feel like I’m being a moron and should stick the questionnaire data in
a require, but that’s just for entire modules, right?


#4

“Michael” == Michael J. removed_email_address@domain.invalid writes:

That’s what I was doing, and it worked just fine, until I added
procedures (proc/lambda) for validation and branching code. Procs seem
really useful under the problem at hand, but they make the questions
unserializable.

They also make your questions sound more like full-on model classes
than as instances of the same model class. Have you considered making
a general Question class and then subclasses of that for each variant
of code you need?

I feel like I’m being a moron and should stick the questionnaire data in
a require, but that’s just for entire modules, right?

It’s for including code, so I can’t see why you wouldn’t do it that
way. If you can load all your questions once at startup, it should
work fine.

	     Calle D. <removed_email_address@domain.invalid>
	 http://www.livejournal.com/users/cdybedahl/
 "Last week was a nightmare, never to be repeated - until this week"
			-- Tom, a.s.r

#5

Michael J. wrote:

Hello RoR!

I’m building a rails app for hosting multi-page surveys. I set up
questionnaire, question, and question_component models. Now I’m
initializing them with some data.

survey.rb
q1 = Question.new “q1”
q1.quote “Welcome to a test of the new interviewing system.”

q2 = Question.new “q2”
q2.quote “Do you like pie?”
q2.single 1 => “Yes”, 2 => “No”
q2.validation_block = Proc.new { [1,2].include?
@interview.answers[“2”] }

questionnaire.questions.concat [q1, q2]

– Real-life questionnaires can be thousands of questions long!

How horrible would it be if I initialized the questionnaire.questions
object, on each request, by reading survey.rb from disk and evaling it?

Hello Michael,

I’m also working on a “questionnaire” system. The solution I came up
with is to store the definition of each question in a separate file (in
the file system). In addition, you have a “map” file which defines the
overall sequence of questions – each question being uniquely identified
by its name for example. This way you only need to read in one question
at a time – and in such a system each request usually relates to just
one question. This avoids the overhead of reading the entire
questionnaire definition for each request. After each request you can
allow the question object to be discarded provided you have first saved
the user’s answer data. All you need to preserve between requests is the
“map” structure (which can be serialised) and the user response data
(which can be serialised or put in a database record, etc).

One reference I have found useful is SCORM (google for it). SCORM is a
standardised way of looking at the architecture of online learning
activities – and questionnaires are very similar.

If you want to clean up your question definitions, this article about
domain specific languages in Ruby is worth reading:

http://jamis.jamisbuck.org/articles/2006/04/20/writing-domain-specific-languages

Paul Howson
(Qld Australia)