Extending the Question and QuestionList Interfaces
by tdaxp ~ July 2nd, 2007
Not going to change the experimental code yet — that’s too big for this day of vacation, whatever I said previously.
Today we’ll improve the student interface to allow questions to be ordered, question lists to be ordered, and a new “question” type (instruction) to be added.

My props to Geek Skillz and Programming Ruby‘s “class Hash” for coming in useful today.
First, go into app/models/question_type-rb and add a new QuestionType item
QuestionType.add_item :INSTRUCTION, 6
Then create a new module, TextfieldType (app/modles/textfield_type.rb) with the following code:
class TextfieldType
def self.add_item(key,value)
@hash ||= {}
@hash[key]=value
end
def self.const_missing(key)
@hash[key]
end
def self.each
@hash.each {|key,value| yield(key,value)}
end
def self.find_selection_list
@hash
end
TextfieldType.add_item :TEXT, 1
TextfieldType.add_item :HTML, 2
end
Then create two migrations, because we will add ordering to both Questions and QuestionLists
ruby script/generate migration alter_questions_add_ordering
ruby script/generate migration alter_questionlists_add_ordering
022_alter_questions_add_ordering.rb reads:
class AlterQuestionsAddOrdering < ActiveRecord::Migration
def self.up
add_column :questions,
rdering, :integer
end
def self.down
remove_column :question_lists,
rdering
end
end
while 023_alter_questionlists_add_ordering.rb is:
class AlterQuestionlistsAddOrdering < ActiveRecord::Migration
def self.up
add_column :question_lists,
rdering, :integer
end
def self.down
remove_column :question_lists,
rdering
end
end
Then rake db:migrate.
Update app/views/manage_questions/list.rhtml:
<h1>Listing questions</h1>
<% form_tag :action => ‘update_ordering’ do %>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Order</th>
<th>Display</th>
<th>Type</th>
<th>Question List</th>
</tr>
<% for question in @questions %>
<tr>
<td><%= question.id %></td>
<td><%= question.name %></td>
<td><%= text_field :question_ordering, question.id, :value => question.ordering, :size=>3 %></td>
<td><%= question.display_text %></td>
<td><%= question.type_id %></td>
<td><%= QuestionList.find_name_by_id(question.list_id) %></td>
<td><%= link_to ‘Show’, :action => ‘show’, :id => question %></td>
<td><%= link_to ‘Edit’, :action => ‘edit’, :id => question %></td>
<td><%= link_to ‘Destroy’, { :action => ‘destroy’, :id => question }, :confirm => ‘Are you sure?’, :method => :post %></td>
</tr>
<% end %>
</table>
<%= link_to ‘Previous page’, { :page => @question_pages.current.previous } if @question_pages.current.previous %>
<%= link_to ‘Next page’, { :page => @question_pages.current.next } if @question_pages.current.next %>
<br /><%= submit_tag ‘Update Ordering’ %>
<br /><%= link_to ‘New question’, :action => ‘new’ %>
<% end %>
In manage_questions_controller.rb, create the new function update_ordering
def update_ordering
@questions_to_order = params[:question_ordering]
@questions_to_order.each { |question_id, new_ordering_value|
if new_ordering_value
@question = Question.find(question_id)
@question.ordering = new_ordering_value
@question.save
end
}
flash[:notice] = "Ordering updated as appropriate"
redirect_to :action => ‘list’
end
And update def list as so:
def list
@question_pages, @questions = paginate :questions, :per_page => 10,
rder => ‘Ordering ASC, ID ASC’
end
After a short break, I realize a problem: putting Ordering in the Questions table makes sense, because each Question is in only one QuestionList table. However, each QuestionList can be in multiple conditions, so Ordering has to go out of QuestionList and into QuestionListConditions; So create a new migration
ruby script/generate migration move_order_from_questionlist_to_questionlistcondition
that file looks like:
class MoveOrderFromQuestionlistToQuestionconditionlist < ActiveRecord::Migration
def self.up
remove_column :question_lists,
rdering
add_column :question_list_conditions,
rdering, :integer
end
def self.down
add_column :question_lists,
rdering, :integer
remove_column :question_list_conditions,
rdering
end
end
Then rake db:migrate.
Now back to the main job
create a new function for the QuestionListCondition model:
def self.find_by_condition_id(condition_id)
to_find = find(:all,:conditions=> {:condition_id => condition_id },
rder => "Ordering, question_list_id")
end
UPdate app/views/manage_question_lists/list.rhtml:
<h1>Listing question_lists</h1>
<% form_tag :action => ‘update_ordering’ do %>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Order</th>
<th>Description</th>
</tr>
<% for question_list in @question_lists %>
<tr>
<td><%= h question_list.id %></td>
<td><%= h question_list.name %></td>
<td>(varies)</td>
<td><%= h question_list.description %></td>
<td><%= link_to ‘Show’, :action => ‘show’, :id => question_list %></td>
<td><%= link_to ‘Edit’, :action => ‘edit’, :id => question_list %></td>
<td><%= link_to ‘Destroy’, { :action => ‘destroy’, :id => question_list }, :confirm => ‘Are you sure?’, :method => :post %></td>
</tr>
<% end %>
<% for experiment in @experiments %>
<% @conditions = Condition.find_conditions_array(experiment.id) %>
<% for condition in @conditions %>
<tr><td colspan="7"> </td></tr>
<tr><td colspan="7"><b><%= experiment.name %> – <%= condition.name %></b></td></tr>
<% @question_list_conditions = QuestionListCondition.find_by_condition_id(condition.id) %>
<% for question_list_condition in @question_list_conditions %>
<% question_list = QuestionList.find(question_list_condition.question_list_id) %>
<tr>
<td><%= h question_list.id %></td>
<td><%= h question_list.name %></td>
<td><%= text_field :question_ordering, question_list_condition.id, :value => question_list_condition.ordering, :size=>3 %></td>
<td><%= h question_list.description %></td>
<td><%= link_to ‘Show’, :action => ‘show’, :id => question_list %></td>
<td><%= link_to ‘Edit’, :action => ‘edit’, :id => question_list %></td>
<td><%= link_to ‘Destroy’, { :action => ‘destroy’, :id => question_list }, :confirm => ‘Are you sure?’, :method => :post %></td>
</tr>
<% end %>
<% end %>
<% end %>
</table>
<%= link_to ‘Previous page’, { :page => @question_list_pages.current.previous } if @question_list_pages.current.previous %>
<%= link_to ‘Next page’, { :page => @question_list_pages.current.next } if @question_list_pages.current.next %>
<br /><%= submit_tag ‘Update Ordering’ %>
<% end %>
<br />s<%= link_to ‘New question_list’, :action => ‘new’ %>
Update app/controllers/manage_question_lists_controller.rb, in the function list
def list
@question_list_pages, @question_lists = paginate :question_lists, :per_page => 10
@experiments = Experiment.find(:all)
end
and create a new function, update ordering (remember we wrote a very similar function for the questions controller):
def update_ordering
@questions_to_order = params[:question_ordering]
@questions_to_order.each { |question_list_condition_id, new_ordering_value|
if new_ordering_value
@question = QuestionListCondition.find(question_list_condition_id)
@question.ordering = new_ordering_value
@question.save
end
}
flash[:notice] = "Ordering updated as appropriate"
redirect_to :action => ‘list’
end
The next day of work will, hopefully, upgrade the experiment interface