Extending the Question and QuestionList Interfaces

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, :ordering, :integer
end

def self.down
remove_column :question_lists, :ordering
end
end

while 023_alter_questionlists_add_ordering.rb is:

class AlterQuestionlistsAddOrdering < ActiveRecord::Migration
def self.up
add_column :question_lists, :ordering, :integer
end

def self.down
remove_column :question_lists, :ordering
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, :order => ‘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, :ordering
add_column :question_list_conditions, :ordering, :integer
end

def self.down
add_column :question_lists, :ordering, :integer
remove_column :question_list_conditions, :ordering
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 }, :order => "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

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>