<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jli53</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jli53"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Jli53"/>
	<updated>2026-05-22T01:19:52Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96752</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96752"/>
		<updated>2015-04-22T18:10:15Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Drop one-person topics */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if diff&amp;gt;0&lt;br /&gt;
  dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
  change_item_type(dj.id)&lt;br /&gt;
  due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
  if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
  if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;%if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),{:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',:id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def drop_outstanding_reviews&lt;br /&gt;
  reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
  for review in reviews&lt;br /&gt;
    review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
    if review_has_began.size.zero?&lt;br /&gt;
      review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
      review_to_drop.first.destroy&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
  drop_outstanding_reviews&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
  assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
  if(assignment.team_assignment?)&lt;br /&gt;
    emails = get_one_member_team&lt;br /&gt;
    email_reminder(emails, self.deadline_type)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def drop_one_member_topics&lt;br /&gt;
  teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
  for team_id in teams.keys&lt;br /&gt;
    if teams[team_id] == 1&lt;br /&gt;
      topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
      if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
        topic_to_drop.delete&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
  assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
  if(assignment.team_assignment?)&lt;br /&gt;
    drop_one_member_topics&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well.&lt;br /&gt;
In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When team_formation deadline is created, there will be two delayed jobs created. One is reminder email and the other one is drop topics from students who don't have a team yet.&lt;br /&gt;
For the functionality of keeping log of scheduled tasks, &amp;quot;has_paper_trail_spec.rb&amp;quot; file is used to make sure that when a delayed job instance is created, one log will be generated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require 'rails_helper'&lt;br /&gt;
describe 'has_paper_trail' do&lt;br /&gt;
  it &amp;quot;will create Version record when create delayed jobs record&amp;quot; do&lt;br /&gt;
    PaperTrail.enabled =true&lt;br /&gt;
    for version in Version.all&lt;br /&gt;
      version.delete&lt;br /&gt;
    end&lt;br /&gt;
    Version.all.count.should == 0&lt;br /&gt;
    @delayed_job = DelayedJob.new&lt;br /&gt;
    @delayed_job.id = 1&lt;br /&gt;
    @delayed_job.priority = 1&lt;br /&gt;
    @delayed_job.attempts = 0&lt;br /&gt;
    @delayed_job.save&lt;br /&gt;
    Version.all.count.should == 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96751</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96751"/>
		<updated>2015-04-22T18:09:40Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Send team formation Emails */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if diff&amp;gt;0&lt;br /&gt;
  dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
  change_item_type(dj.id)&lt;br /&gt;
  due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
  if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
  if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;%if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),{:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',:id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def drop_outstanding_reviews&lt;br /&gt;
  reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
  for review in reviews&lt;br /&gt;
    review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
    if review_has_began.size.zero?&lt;br /&gt;
      review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
      review_to_drop.first.destroy&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
  drop_outstanding_reviews&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
  assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
  if(assignment.team_assignment?)&lt;br /&gt;
    emails = get_one_member_team&lt;br /&gt;
    email_reminder(emails, self.deadline_type)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well.&lt;br /&gt;
In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When team_formation deadline is created, there will be two delayed jobs created. One is reminder email and the other one is drop topics from students who don't have a team yet.&lt;br /&gt;
For the functionality of keeping log of scheduled tasks, &amp;quot;has_paper_trail_spec.rb&amp;quot; file is used to make sure that when a delayed job instance is created, one log will be generated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require 'rails_helper'&lt;br /&gt;
describe 'has_paper_trail' do&lt;br /&gt;
  it &amp;quot;will create Version record when create delayed jobs record&amp;quot; do&lt;br /&gt;
    PaperTrail.enabled =true&lt;br /&gt;
    for version in Version.all&lt;br /&gt;
      version.delete&lt;br /&gt;
    end&lt;br /&gt;
    Version.all.count.should == 0&lt;br /&gt;
    @delayed_job = DelayedJob.new&lt;br /&gt;
    @delayed_job.id = 1&lt;br /&gt;
    @delayed_job.priority = 1&lt;br /&gt;
    @delayed_job.attempts = 0&lt;br /&gt;
    @delayed_job.save&lt;br /&gt;
    Version.all.count.should == 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96750</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96750"/>
		<updated>2015-04-22T18:09:11Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Drop outstanding reviews */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if diff&amp;gt;0&lt;br /&gt;
  dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
  change_item_type(dj.id)&lt;br /&gt;
  due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
  if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
  if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;%if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),{:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',:id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def drop_outstanding_reviews&lt;br /&gt;
  reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
  for review in reviews&lt;br /&gt;
    review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
    if review_has_began.size.zero?&lt;br /&gt;
      review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
      review_to_drop.first.destroy&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
  drop_outstanding_reviews&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          emails = get_one_member_team&lt;br /&gt;
          email_reminder(emails, self.deadline_type)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well.&lt;br /&gt;
In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When team_formation deadline is created, there will be two delayed jobs created. One is reminder email and the other one is drop topics from students who don't have a team yet.&lt;br /&gt;
For the functionality of keeping log of scheduled tasks, &amp;quot;has_paper_trail_spec.rb&amp;quot; file is used to make sure that when a delayed job instance is created, one log will be generated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require 'rails_helper'&lt;br /&gt;
describe 'has_paper_trail' do&lt;br /&gt;
  it &amp;quot;will create Version record when create delayed jobs record&amp;quot; do&lt;br /&gt;
    PaperTrail.enabled =true&lt;br /&gt;
    for version in Version.all&lt;br /&gt;
      version.delete&lt;br /&gt;
    end&lt;br /&gt;
    Version.all.count.should == 0&lt;br /&gt;
    @delayed_job = DelayedJob.new&lt;br /&gt;
    @delayed_job.id = 1&lt;br /&gt;
    @delayed_job.priority = 1&lt;br /&gt;
    @delayed_job.attempts = 0&lt;br /&gt;
    @delayed_job.save&lt;br /&gt;
    Version.all.count.should == 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96749</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96749"/>
		<updated>2015-04-22T18:08:35Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Keep log of the scheduled tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if diff&amp;gt;0&lt;br /&gt;
  dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
  change_item_type(dj.id)&lt;br /&gt;
  due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
  if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
  if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;%if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),{:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',:id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_outstanding_reviews&lt;br /&gt;
    reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
    for review in reviews&lt;br /&gt;
      review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
      if review_has_began.size.zero?&lt;br /&gt;
        review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
        review_to_drop.first.destroy&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
        drop_outstanding_reviews&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          emails = get_one_member_team&lt;br /&gt;
          email_reminder(emails, self.deadline_type)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well.&lt;br /&gt;
In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When team_formation deadline is created, there will be two delayed jobs created. One is reminder email and the other one is drop topics from students who don't have a team yet.&lt;br /&gt;
For the functionality of keeping log of scheduled tasks, &amp;quot;has_paper_trail_spec.rb&amp;quot; file is used to make sure that when a delayed job instance is created, one log will be generated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require 'rails_helper'&lt;br /&gt;
describe 'has_paper_trail' do&lt;br /&gt;
  it &amp;quot;will create Version record when create delayed jobs record&amp;quot; do&lt;br /&gt;
    PaperTrail.enabled =true&lt;br /&gt;
    for version in Version.all&lt;br /&gt;
      version.delete&lt;br /&gt;
    end&lt;br /&gt;
    Version.all.count.should == 0&lt;br /&gt;
    @delayed_job = DelayedJob.new&lt;br /&gt;
    @delayed_job.id = 1&lt;br /&gt;
    @delayed_job.priority = 1&lt;br /&gt;
    @delayed_job.attempts = 0&lt;br /&gt;
    @delayed_job.save&lt;br /&gt;
    Version.all.count.should == 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96748</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96748"/>
		<updated>2015-04-22T18:08:11Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Add UI to visualize for scheduled tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if diff&amp;gt;0&lt;br /&gt;
  dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
  change_item_type(dj.id)&lt;br /&gt;
  due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
  if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
  if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;%if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;%if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),{:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',:id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_outstanding_reviews&lt;br /&gt;
    reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
    for review in reviews&lt;br /&gt;
      review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
      if review_has_began.size.zero?&lt;br /&gt;
        review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
        review_to_drop.first.destroy&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
        drop_outstanding_reviews&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          emails = get_one_member_team&lt;br /&gt;
          email_reminder(emails, self.deadline_type)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well.&lt;br /&gt;
In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When team_formation deadline is created, there will be two delayed jobs created. One is reminder email and the other one is drop topics from students who don't have a team yet.&lt;br /&gt;
For the functionality of keeping log of scheduled tasks, &amp;quot;has_paper_trail_spec.rb&amp;quot; file is used to make sure that when a delayed job instance is created, one log will be generated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require 'rails_helper'&lt;br /&gt;
describe 'has_paper_trail' do&lt;br /&gt;
  it &amp;quot;will create Version record when create delayed jobs record&amp;quot; do&lt;br /&gt;
    PaperTrail.enabled =true&lt;br /&gt;
    for version in Version.all&lt;br /&gt;
      version.delete&lt;br /&gt;
    end&lt;br /&gt;
    Version.all.count.should == 0&lt;br /&gt;
    @delayed_job = DelayedJob.new&lt;br /&gt;
    @delayed_job.id = 1&lt;br /&gt;
    @delayed_job.priority = 1&lt;br /&gt;
    @delayed_job.attempts = 0&lt;br /&gt;
    @delayed_job.save&lt;br /&gt;
    Version.all.count.should == 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96747</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96747"/>
		<updated>2015-04-22T18:06:39Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Add UI to visualize for scheduled tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if diff&amp;gt;0&lt;br /&gt;
  dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
  change_item_type(dj.id)&lt;br /&gt;
  due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
  if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
  if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
    dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)), 1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;% if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),&lt;br /&gt;
                            {:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',&lt;br /&gt;
                             :id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_outstanding_reviews&lt;br /&gt;
    reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
    for review in reviews&lt;br /&gt;
      review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
      if review_has_began.size.zero?&lt;br /&gt;
        review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
        review_to_drop.first.destroy&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
        drop_outstanding_reviews&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          emails = get_one_member_team&lt;br /&gt;
          email_reminder(emails, self.deadline_type)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well.&lt;br /&gt;
In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When team_formation deadline is created, there will be two delayed jobs created. One is reminder email and the other one is drop topics from students who don't have a team yet.&lt;br /&gt;
For the functionality of keeping log of scheduled tasks, &amp;quot;has_paper_trail_spec.rb&amp;quot; file is used to make sure that when a delayed job instance is created, one log will be generated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require 'rails_helper'&lt;br /&gt;
describe 'has_paper_trail' do&lt;br /&gt;
  it &amp;quot;will create Version record when create delayed jobs record&amp;quot; do&lt;br /&gt;
    PaperTrail.enabled =true&lt;br /&gt;
    for version in Version.all&lt;br /&gt;
      version.delete&lt;br /&gt;
    end&lt;br /&gt;
    Version.all.count.should == 0&lt;br /&gt;
    @delayed_job = DelayedJob.new&lt;br /&gt;
    @delayed_job.id = 1&lt;br /&gt;
    @delayed_job.priority = 1&lt;br /&gt;
    @delayed_job.attempts = 0&lt;br /&gt;
    @delayed_job.save&lt;br /&gt;
    Version.all.count.should == 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96746</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96746"/>
		<updated>2015-04-22T18:02:50Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  if diff&amp;gt;0&lt;br /&gt;
    dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)),&lt;br /&gt;
                            1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
    due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
    # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
    if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
      dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)),&lt;br /&gt;
                              1, diff.minutes.from_now)&lt;br /&gt;
      change_item_type(dj.id)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
    if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
      dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)),&lt;br /&gt;
                           1, diff.minutes.from_now)&lt;br /&gt;
      change_item_type(dj.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;% if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),&lt;br /&gt;
                            {:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',&lt;br /&gt;
                             :id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_outstanding_reviews&lt;br /&gt;
    reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
    for review in reviews&lt;br /&gt;
      review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
      if review_has_began.size.zero?&lt;br /&gt;
        review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
        review_to_drop.first.destroy&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
        drop_outstanding_reviews&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          emails = get_one_member_team&lt;br /&gt;
          email_reminder(emails, self.deadline_type)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well.&lt;br /&gt;
In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When team_formation deadline is created, there will be two delayed jobs created. One is reminder email and the other one is drop topics from students who don't have a team yet.&lt;br /&gt;
For the functionality of keeping log of scheduled tasks, &amp;quot;has_paper_trail_spec.rb&amp;quot; file is used to make sure that when a delayed job instance is created, one log will be generated.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require 'rails_helper'&lt;br /&gt;
describe 'has_paper_trail' do&lt;br /&gt;
  it &amp;quot;will create Version record when create delayed jobs record&amp;quot; do&lt;br /&gt;
    PaperTrail.enabled =true&lt;br /&gt;
    for version in Version.all&lt;br /&gt;
      version.delete&lt;br /&gt;
    end&lt;br /&gt;
    Version.all.count.should == 0&lt;br /&gt;
    @delayed_job = DelayedJob.new&lt;br /&gt;
    @delayed_job.id = 1&lt;br /&gt;
    @delayed_job.priority = 1&lt;br /&gt;
    @delayed_job.attempts = 0&lt;br /&gt;
    @delayed_job.save&lt;br /&gt;
    Version.all.count.should == 1&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96745</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96745"/>
		<updated>2015-04-22T17:57:21Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  if diff&amp;gt;0&lt;br /&gt;
    dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)),&lt;br /&gt;
                            1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
    due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
    # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
    if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
      dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)),&lt;br /&gt;
                              1, diff.minutes.from_now)&lt;br /&gt;
      change_item_type(dj.id)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
    if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
      dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)),&lt;br /&gt;
                           1, diff.minutes.from_now)&lt;br /&gt;
      change_item_type(dj.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;% if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),&lt;br /&gt;
                            {:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',&lt;br /&gt;
                             :id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_outstanding_reviews&lt;br /&gt;
    reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
    for review in reviews&lt;br /&gt;
      review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
      if review_has_began.size.zero?&lt;br /&gt;
        review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
        review_to_drop.first.destroy&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
        drop_outstanding_reviews&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          emails = get_one_member_team&lt;br /&gt;
          email_reminder(emails, self.deadline_type)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well. In &amp;quot;scheduled_task_spec.rb&amp;quot;, we test the functionality that when a due date is created, then delayed jobs of certain deadline type will be created. We may take &amp;quot;team_formation&amp;quot; deadline as an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe 'Team formation deadline reminder email' do&lt;br /&gt;
&lt;br /&gt;
  it 'should send reminder email for team formation deadline to reviewers ' do&lt;br /&gt;
&lt;br /&gt;
    id = 2&lt;br /&gt;
    @name = &amp;quot;user&amp;quot;&lt;br /&gt;
    due_at = DateTime.now.advance(:minutes =&amp;gt; +2)&lt;br /&gt;
&lt;br /&gt;
    due_at1 = Time.parse(due_at.to_s(:db))&lt;br /&gt;
    curr_time=DateTime.now.to_s(:db)&lt;br /&gt;
    curr_time=Time.parse(curr_time)&lt;br /&gt;
    time_in_min=((due_at1 - curr_time).to_i/60) *60&lt;br /&gt;
    Delayed::Job.delete_all&lt;br /&gt;
    Delayed::Job.count.should == 0&lt;br /&gt;
&lt;br /&gt;
    dj = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;team_formation&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 1&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: team_formation&amp;quot;)&lt;br /&gt;
    dj2 = Delayed::Job.enqueue(ScheduledTask.new(id, &amp;quot;drop_one_member_topics&amp;quot;, due_at), 1, time_in_min)&lt;br /&gt;
    Delayed::Job.count.should == 2&lt;br /&gt;
    Delayed::Job.last.handler.should include(&amp;quot;deadline_type: drop_one_member_topics&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96744</id>
		<title>CSC/ECE 517 Spring 2015 E1529 GLDS</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015_E1529_GLDS&amp;diff=96744"/>
		<updated>2015-04-22T17:48:25Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;E1529. Extend the Email notification feature to scheduled tasks &amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities&amp;lt;ref&amp;gt;[https://github.com/expertiza/expertiza Expertiza Github]&amp;lt;/ref&amp;gt;. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc). It is also a powerful tool for professor to manage courses and assignments and so on. The latest &amp;quot;Rails 4&amp;quot; branch of Expertiza, although combined with various enhancements from the past two years, is seriously broken, from data migration to key feature implementation. Part of the reason has been the design strategy and code changes by various teams.&lt;br /&gt;
&lt;br /&gt;
==Email notification feature to scheduled tasks==&lt;br /&gt;
This is a feature that has already been partially implemented in Expertiza [https://github.com/expertiza/expertiza/pull/445 E1451] implemented both sychronous and asychoronous mailers. Sychronous Emails refer to the Emails sent immediatly after an event (e.g. when student receive a peer-review). Asychoronous Email we implemented by the Gem &amp;quot;delayed job” and when a task (asychronous Email) is added to the delayed queue, a count-down number of minutes needs to be specified.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our team aims to extend this project. This wiki page documents the problem analysis and provides a guideline for future development and enhancement.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=Scope=&lt;br /&gt;
==Project Scope==&lt;br /&gt;
E1451. ​Create Mailers for All Email Messages [https://github.com/expertiza/expertiza/pull/445 github] [http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2014/OSS_E1451_las wiki] [http://expertiza.ncsu.edu/submitted_content/download/28122?current_folder%5Bname%5D=%2Flocal%2Frails%2Fexpertiza%2Freleases%2F20140702225848%2Fpg_data%2Fefg%2Fcsc517%2Ff14%2F%2F18&amp;amp;download=E1451_Report.pdf report] (Merged in [https://docs.google.com/a/ncsu.edu/document/d/1aypHb5UOe-3nPfruNeh2HZjeT-wfv6f-ZsZg2jDMNkQ/edit E1483])&lt;br /&gt;
&lt;br /&gt;
Extending this project, the new system should be capable of&lt;br /&gt;
*If one task is added to the delayed job queue, the asychronous Email should be updated or deleted automatically.&lt;br /&gt;
*Add UI to visualize for the task in delayed job queue, instructors should be able to view tasks related to the assignments they have created. 	&lt;br /&gt;
*Keep log of the scheduled tasks when they are scheduled and done, record events in the same log as project [https://github.com/expertiza/expertiza/pull/462 E​1478].		&lt;br /&gt;
*[optional] support more scheduled task:  							 &lt;br /&gt;
**instructors are able to schedule the time to drop all the outstanding reviews (reviews which has not been started) &lt;br /&gt;
**instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one. &lt;br /&gt;
**(new) instructor should be able to schedule a time to drop all the topics which are held by 1 person teams.&lt;br /&gt;
*create tests to make sure the test coverage increases.&lt;br /&gt;
==Files Involved==&lt;br /&gt;
Mailers:&lt;br /&gt;
*delayed_mailer.rb&lt;br /&gt;
&lt;br /&gt;
Models:&lt;br /&gt;
*assignment_form.rb&lt;br /&gt;
*due_date.rb&lt;br /&gt;
*delayed_job.rb(new created)&lt;br /&gt;
*scheduled_task.rb(new created)&lt;br /&gt;
&lt;br /&gt;
Views:&lt;br /&gt;
*_due_dates.html.erb&lt;br /&gt;
*_assignments_actions.html.erb&lt;br /&gt;
*  scheduled_tasks.erb(new created)&lt;br /&gt;
&lt;br /&gt;
Controllers:&lt;br /&gt;
*assignments_controller.rb&lt;br /&gt;
&lt;br /&gt;
==Gems Related==&lt;br /&gt;
*gem 'delayed_job_active_record' &lt;br /&gt;
&lt;br /&gt;
[https://github.com/collectiveidea/delayed_job Delayed:Job] encapsulates the common pattern of asynchronously executing longer tasks in the background&amp;lt;ref&amp;gt; [https://github.com/collectiveidea/delayed_job Delayed_job Gem]&amp;lt;/ref&amp;gt;. It allows to support multiple backends for storing the job queue.  By using 'delayed_job_active_record'  gem, we can use delayed_job with Active Record. This Active Record backend requires a job table. &lt;br /&gt;
&lt;br /&gt;
After running rails generate delayed_job:active_record and rake db:migrate, a &amp;quot;delayed_jobs&amp;quot; table is created in our database. This gem integrates well with many [http://en.wikipedia.org/wiki/Relational_database_management_system RDBMS] backend such as MySQL. Using this gem, we can store all scheduled tasks queue into the &amp;quot;delayed_jobs&amp;quot; table.&lt;br /&gt;
&lt;br /&gt;
*gem 'paper_trail'&lt;br /&gt;
PaperTrail allows to track changes of models' data, which is good for versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed&amp;lt;ref&amp;gt;[https://github.com/airblade/paper_trail Paper_trail Gem]&amp;lt;/ref&amp;gt;. Using this gem, we can keep log of the scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
=Problem Analysis=&lt;br /&gt;
&lt;br /&gt;
== Time Issues==&lt;br /&gt;
&lt;br /&gt;
Initially,  when we want to verify the email function, we found many time issues in this system. That blocks our work about email notification. Some related problems are explained and analyzed in this section. &lt;br /&gt;
&lt;br /&gt;
===Wrong displayed time===&lt;br /&gt;
&lt;br /&gt;
Firstly, when we set a due time to test the mail features, we found the display of time is incorrect.&lt;br /&gt;
&lt;br /&gt;
In the “Assignment Edit”-&amp;gt;“Due dates”, when we modify the “Date &amp;amp; time” of the deadline, the displayed time will be 4 hours ahead of the time we saved.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time.png‎ |frame|center|Set due time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Wrong display of time 2.png |frame|center|After we click the save button, we can see that all the time are 4 hours ahead of the set time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:database_deadline.png |frame|center|The deadline time is stored correct in the database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After several tries, we found that every time when we click &amp;quot;save&amp;quot;, the saved time is 4 hours earlier then the last saved time. However, the time in the database is alway correct as the time we save. After we analyze, we found the problem may lay in the line of 68 of &amp;lt;code&amp;gt;views/assignment/edit/_due_dates.html.erb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;due_at = new Date(due_at.substr(0, 16)).format('yyyy/mm/dd HH:MM');&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When we declare a Data object, this Data() function will perform a time zone conversion automatically. Yet Rails’ default timezone stored in database is UTC. So the displayed time(local time, which is EDT) and time in database is different.&lt;br /&gt;
&lt;br /&gt;
===Different time zone===&lt;br /&gt;
&lt;br /&gt;
In the previous version, when current time is compared with the time stored in database, they may apply to different time zones so that the result of comparison may be wrong.&amp;lt;br&amp;gt;&lt;br /&gt;
When we delay a deadline of an assignment, for example, we set the deadline of metareview from2015/03/28 16:00 to 2015/04/04 20:00 and set the reminder hr to 16 hours.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Delayassign.png |frame|center|Delay a time]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After click &amp;quot;save&amp;quot;, the run time showed database is about 8:00 am. Since 20-16=4, the correct run time is 4:00 am.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:delaydatabase.png |frame|center|Time Stored in Database]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reason why there is a four-hour time difference is generated from the file &amp;lt;code&amp;gt;application_form.rb&amp;lt;/code&amp;gt;, method &amp;lt;code&amp;gt; find_min_from_now(due_at)&amp;lt;/code&amp;gt;, and line 142 &amp;lt;code&amp;gt;time_in_min=((due_at - curr_time).to_i/60)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt; due_at &amp;lt;/code&amp;gt; is the system time for Rails (UTC), while &amp;lt;code&amp;gt; curr_time &amp;lt;/code&amp;gt; is the local time which is EDT. The two time zones have four-hour time difference.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===New deadline replace the old one===&lt;br /&gt;
This time, we add a new delay in Review section, we delay the deadline from 2015/03/22 21:00 to 2015/03/30 21:00, and set the remind hr to 8 hours.&lt;br /&gt;
&lt;br /&gt;
[[File:delayagain.png |frame|center|Delay a new deadline type]]&lt;br /&gt;
&lt;br /&gt;
However, the delayed_jobs database form is still the same, which means in one assignment there is only one reminder can work.&amp;lt;br&amp;gt;&lt;br /&gt;
As a result, we conclude that only one due_time record associated with different period exists in the database:&lt;br /&gt;
*In Expertiza, one assignment has several period, such as submission, review, metareview. Administrates are able to set and postpone due dates for each period separately.&lt;br /&gt;
*In the previous version, when the instructor postpone the review deadline and then postpone the submit deadline, the submit deadline’s modification will replace the the review deadline’s modification in database. &lt;br /&gt;
*In this case, if both of them need Email reminder, there will be no Email about the former modified deadline.&lt;br /&gt;
*After our analysis, we found the due time object is identified with assignment_id, instead of deadline type id.&lt;br /&gt;
&lt;br /&gt;
==UI issues==&lt;br /&gt;
In the previous version, there is no UI to display the reminders of assignments. There is no way for instructors to view or delete their delayed tasks related to an assignment. We are going to add a button under Assignment-&amp;gt;edit, and add a view to display all delayed jobs derived from the delayed_jobs table in our database.&lt;br /&gt;
&lt;br /&gt;
=System Design=&lt;br /&gt;
==Fix Time Issues==&lt;br /&gt;
===Unified time zone===&lt;br /&gt;
We convert current time to the same time zone as the deadline stored in database. Then the result of comparison will be right so that it can be used for further usage.&lt;br /&gt;
In &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt;, we modified &amp;lt;code&amp;gt;curr_time=DateTime.now.to_s(:db)&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;curr_time=DateTime.now.in_time_zone(zone='UTC').to_s(:db)&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;find_min_from_now&amp;lt;/code&amp;gt; method, to make sure when calculating the minutes from now, the time zone is right.&amp;lt;br&amp;gt;&lt;br /&gt;
Also, to make sure the right display of time, when log in as a administrator, go to Profile and choose the Preferred Time Zone to be &amp;quot;(GMT-05:00) Eastern Time (US&amp;amp;Canada)&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Separate deadline of each topic period===&lt;br /&gt;
In each Assignment, each deadline type (E.g review, submit, metareview) should has its own Email reminder time in the database. New postponed deadline of one type can only replace the same deadline type in the same assignment id category. This bug has been fixed by TA.&lt;br /&gt;
&lt;br /&gt;
==Add UI to visualize for scheduled tasks==&lt;br /&gt;
All the scheduled tasks are in the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table in database, so the system will read from that table to show all the tasks‘ information. A new page is created to show all of those scheduled tasks and there is also a delete button for instructor to delete any task. Instructor can view this page via a &amp;lt;code&amp;gt;view delayed jobs&amp;lt;/code&amp;gt; button in &amp;lt;code&amp;gt; assignment-&amp;gt;edit &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
The code in &amp;lt;code&amp;gt;app/models/assignment_form.rb&amp;lt;/code&amp;gt; add the scheduled tasks into &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  if diff&amp;gt;0&lt;br /&gt;
    dj=DelayedJob.enqueue(ScheduledTask.new(@assignment.id, deadline_type, due_date.due_at.to_s(:db)),&lt;br /&gt;
                            1, diff.minutes.from_now)&lt;br /&gt;
    change_item_type(dj.id)&lt;br /&gt;
    due_date.update_attribute(:delayed_job_id, dj.id)&lt;br /&gt;
&lt;br /&gt;
    # If the deadline type is review, add a delayed job to drop outstanding review&lt;br /&gt;
    if deadline_type == &amp;quot;review&amp;quot;&lt;br /&gt;
      dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_outstanding_reviews&amp;quot;, due_date.due_at.to_s(:db)),&lt;br /&gt;
                              1, diff.minutes.from_now)&lt;br /&gt;
      change_item_type(dj.id)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # If the deadline type is team_formation, add a delayed job to drop one member team&lt;br /&gt;
    if deadline_type == &amp;quot;team_formation&amp;quot;&lt;br /&gt;
      dj = DelayedJob.enqueue(ScheduledTask.new(@assignment.id, &amp;quot;drop_one_member_topics&amp;quot;, due_date.due_at.to_s(:db)),&lt;br /&gt;
                           1, diff.minutes.from_now)&lt;br /&gt;
      change_item_type(dj.id)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After adding to the delayed_jobs, the database will store each task's assignment's id, deadline type, due date, task run time etc.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:delayedjobs.png |frame|center|the delayed jobs table in database]]&amp;lt;br&amp;gt;&lt;br /&gt;
We create a file &amp;lt;code&amp;gt;scheduled_tasks.erb&amp;lt;/code&amp;gt; in the path: &amp;lt;code&amp;gt;/views/assignments&amp;lt;/code&amp;gt; to show the form. In this file, we use a &amp;lt;code&amp;gt;@scheduled_jobs = DelayedJob.all &amp;lt;/code&amp;gt; to read all datas from the &amp;quot;delayed_jobs&amp;quot; table. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% @assignment = Assignment.find(params[:id]) %&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;Scheduled tasks for &amp;lt;%= @assignment.name %&amp;gt; assignment&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;% if flash[:notice] %&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;flash_note&amp;quot;&amp;gt;&amp;lt;%= flash_message :notice %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% @scheduled_jobs = DelayedJob.all %&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;general&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Deadline type #&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Run time&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25%&amp;quot;&amp;gt;Due date&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Action&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th width=&amp;quot;25 %&amp;quot;&amp;gt;Delete&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;% i=1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% for delayed_job in @scheduled_jobs %&amp;gt;&lt;br /&gt;
      &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;% if delayed_job.handler.include? &amp;quot;assignment_id: #{@assignment.id}&amp;quot;%&amp;gt;&lt;br /&gt;
            &amp;lt;% handler = delayed_job.handler.split()%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[5] %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= delayed_job.run_at %&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= handler[7][1..-1] + &amp;quot;:&amp;quot; + handler[8][0..-2]%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;submission&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;review&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;metareview&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot; &amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;team_formation&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;send email to ask students to form teams&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_outstanding_reviews&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop outstanding reviews and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;% if handler[5] == &amp;quot;drop_one_member_topics&amp;quot; %&amp;gt;&lt;br /&gt;
                &amp;lt;td&amp;gt;&amp;lt;%= &amp;quot;drop one member team topics and send emails to those students&amp;quot;%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
            &amp;lt;%end%&amp;gt;&lt;br /&gt;
            &amp;lt;td&amp;gt;&amp;lt;%= link_to image_tag('delete_icon.png', :title =&amp;gt; 'Delete'),&lt;br /&gt;
                            {:controller =&amp;gt; 'assignments', :action =&amp;gt; 'delete_scheduled_task',&lt;br /&gt;
                             :id =&amp;gt; @assignment.id, :delayed_job_id =&amp;gt; delayed_job.id}%&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;% end %&amp;gt;&lt;br /&gt;
      &amp;lt;/tr&amp;gt;&lt;br /&gt;
      &amp;lt;% i=i+1 %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;% session[:return_to] = request.url %&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;javascript:history.back()&amp;quot;&amp;gt;Back&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
The following two pictures show our UI works. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:viewdelayedjobs.png |frame|center|add a button to display all scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:showscheduledtask.png|frame|center|The UI to show all the scheduled tasks]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Keep log of the scheduled tasks==&lt;br /&gt;
According to the project [https://github.com/expertiza/expertiza/pull/462 E1478], there is a paper_trail&amp;lt;ref name = &amp;quot;Paper_trail Gem&amp;quot;&amp;gt; https://github.com/airblade/paper_trail]&amp;lt;/ref&amp;gt; gem which can keep log of the models' data. What we need to do is let it also keep track of our scheduled task data.&amp;lt;br&amp;gt;&lt;br /&gt;
Since the gem need to work with &amp;lt;code&amp;gt;ActiveRecord 3+&amp;lt;/code&amp;gt;, while &amp;lt;code&amp;gt;assignment_form&amp;lt;/code&amp;gt; doesn't. So we created a new file named &amp;lt;code&amp;gt;delayed_job.rb&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;models&amp;lt;/code&amp;gt; folder, add &amp;lt;code&amp;gt;has_paper_trail&amp;lt;/code&amp;gt; in it. Then it is like: &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class DelayedJob &amp;lt; Delayed::Job&lt;br /&gt;
  has_paper_trail&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table changes, a &amp;lt;code&amp;gt;Delayed::Backend::ActiveRecord::Job&amp;lt;/code&amp;gt; record is automatically created in the log. In &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt;, we define a method to change the item type displayed in the log.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def change_item_type(delayed_job_id)&lt;br /&gt;
    log = Version.where(item_type: &amp;quot;Delayed::Backend::ActiveRecord::Job&amp;quot;, item_id: delayed_job_id).first&lt;br /&gt;
    log.update_attribute(:item_type, &amp;quot;ScheduledTask&amp;quot;) #Change the item type in the log&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we call it in &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method of the same file. Every time when the &amp;lt;code&amp;gt;delayed_jobs&amp;lt;/code&amp;gt; table has added or deleted or updated data, the log can keep track of them. The following picture shows what the log is after creating scheduled tasks. You can see a &amp;quot;Search log&amp;quot; under the &amp;quot;logout&amp;quot; button. &amp;lt;br&amp;gt;&lt;br /&gt;
[[File:scheduledtasklog.png|frame|center|four scheduled tasks are added in log]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==support more schedule tasks==&lt;br /&gt;
&lt;br /&gt;
In our system, we would have four scheduled time: submission, review, metareview and team_formation. When due time comes, the system takes corresponding actions. These scheduled actions are called scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
[[File:Support more scheduled tasks.png|frame|center|Support more scheduled tasks]]&lt;br /&gt;
&lt;br /&gt;
===Drop outstanding reviews===&lt;br /&gt;
In this task, instructors should be able to schedule a time to drop all the outstanding reviews, which means the reviews which has not been started.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Firstly, we create a new deadline type called &amp;quot;drop_outstanding_reviews&amp;quot;. When we set the review’s due date, add an item into  “delayed job”  queue at the same time( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
When the review is due, it will automatically call a method to find all the outstanding reviews (reviews which have not been started) in the database then delete them. &amp;lt;br&amp;gt;&lt;br /&gt;
There are two tables in the database to store the information about the reviews: &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;response_maps &amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; is used to store all the submitted reviews while &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; stores all the requested reviews, which means if one review has began it will not stored in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; table. Thus, we just need to find the review data in &amp;lt;code&amp;gt;response_maps&amp;lt;/code&amp;gt; while not in &amp;lt;code&amp;gt;responses&amp;lt;/code&amp;gt; for one assignment and delete them in database.&amp;lt;br&amp;gt;&lt;br /&gt;
We add a method in  &amp;lt;code&amp;gt;/models/scheduled_task.rb&amp;lt;/code&amp;gt; named &amp;lt;code&amp;gt;drop_outstanding_reviews&amp;lt;/code&amp;gt; to drop those reviews.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_outstanding_reviews&lt;br /&gt;
    reviews = ResponseMap.where(reviewed_object_id: self.assignment_id)&lt;br /&gt;
    for review in reviews&lt;br /&gt;
      review_has_began = Response.where(map_id: review.id)&lt;br /&gt;
      if review_has_began.size.zero?&lt;br /&gt;
        review_to_drop = ResponseMap.where(id: review.id)&lt;br /&gt;
        review_to_drop.first.destroy&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, add the following code in &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method of the same file to drop one specified assignment's outstanding reviews at the due time.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 if(self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;)&lt;br /&gt;
        drop_outstanding_reviews&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send team formation Emails===&lt;br /&gt;
In this task, the instructors are able to schedule a specific time to send Emails to all the assignment participants who are still not in any team to find or form one.&lt;br /&gt;
We use a previously existed deadline type called &amp;quot;team_formation&amp;quot;  and enable to set a team_formation's due date and a reminder under &amp;quot;Assignment-&amp;gt;edit-&amp;gt;due date&amp;quot;. Then add an item into “delayed job” at the same time(refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).  When “delayed job” is triggered, it will automatically call a method to find all the assignment participants who are still not in any team in the database, and send Emails to them to find teammate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;team_formation&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          emails = get_one_member_team&lt;br /&gt;
          email_reminder(emails, self.deadline_type)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Drop one-person topics===&lt;br /&gt;
In this task, the instructor should be able to schedule a time to drop all the topics which are held by 1 person teams. &lt;br /&gt;
We create a new deadline type called &amp;quot;drop_one_member_topics&amp;quot;. When deadline type is team_formation, we add an item to the &amp;quot;delayed_job&amp;quot; queue( refer to &amp;quot;Add UI to visualize for scheduled tasks&amp;quot;).&lt;br /&gt;
Then when time is due, the system will call a method to find all the topics which are held by 1 person teams in the database, then the professor can drop those topics.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def drop_one_member_topics&lt;br /&gt;
    teams = TeamsUser.all.group(:team_id).count(:team_id)&lt;br /&gt;
    for team_id in teams.keys&lt;br /&gt;
      if teams[team_id] == 1&lt;br /&gt;
        topic_to_drop = SignedUpUser.where(creator_id: team_id).first&lt;br /&gt;
        if topic_to_drop#check if the one-person-team has signed up a topic&lt;br /&gt;
          topic_to_drop.delete&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      if(self.deadline_type == &amp;quot;drop_one_member_topics&amp;quot;)&lt;br /&gt;
        assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
        if(assignment.team_assignment?)&lt;br /&gt;
          drop_one_member_topics&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Tests=&lt;br /&gt;
In this project, our jobs involve two gems as mentioned above. They are &amp;quot;Delayed Job&amp;quot;, which can insert a job into queue and execute it at a certain time, and &amp;quot;Paper Trail&amp;quot;, to log actions like create, update and destroy for a model. We write rspec tests to make sure that the functionality works well. In&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95259</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95259"/>
		<updated>2015-03-21T22:26:50Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Deleting redundant button */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
* Some codes does not follow the [https://docs.google.com/a/ncsu.edu/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;.&lt;br /&gt;
*&amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; has all seven methods in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; with same name. we found these functions are completely achieved via &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;. And after test, we prove that codes in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; never got executed when we ran the project.&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we need to change some references to the method:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
verify method: 'post', :only =&amp;gt; [:destroy, :create, :update],&lt;br /&gt;
:redirect_to =&amp;gt; {:action =&amp;gt; :index}&lt;br /&gt;
&lt;br /&gt;
SignUpTopic.reassign_topic(@user_id,params[:assignment_id], params[:id])&lt;br /&gt;
redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&lt;br /&gt;
signup_team(@assignment.id, @user_id, params[:id])&lt;br /&gt;
redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the origin popup menu is as following picture, there is a&amp;lt;code&amp;gt;edit signup sheet &amp;lt;/code&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:originPopup.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
The new popup menu is:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:new_popup.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
After modifying, the other assignment functions all works well.&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:AssignTopic.png]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name &amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;code&amp;gt;signup_sheet_controller&amp;lt;/code&amp;gt; automatically.&amp;lt;br&amp;gt;&lt;br /&gt;
Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95256</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95256"/>
		<updated>2015-03-21T22:25:55Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Renaming controller */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
* Some codes does not follow the [https://docs.google.com/a/ncsu.edu/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;.&lt;br /&gt;
*&amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; has all seven methods in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; with same name. we found these functions are completely achieved via &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;. And after test, we prove that codes in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; never got executed when we ran the project.&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we need to change some references to the method:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
verify method: 'post', :only =&amp;gt; [:destroy, :create, :update],&lt;br /&gt;
:redirect_to =&amp;gt; {:action =&amp;gt; :index}&lt;br /&gt;
&lt;br /&gt;
SignUpTopic.reassign_topic(@user_id,params[:assignment_id], params[:id])&lt;br /&gt;
redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&lt;br /&gt;
signup_team(@assignment.id, @user_id, params[:id])&lt;br /&gt;
redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the origin popup menu is as following picture, there is a &amp;lt;code&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:originPopup.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
The new popup menu is:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:new_popup.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
After modifying, the other assignment functions all works well.&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:AssignTopic.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;gt;=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name &amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;code&amp;gt;signup_sheet_controller&amp;lt;/code&amp;gt; automatically.&amp;lt;br&amp;gt;&lt;br /&gt;
Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95244</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95244"/>
		<updated>2015-03-21T22:06:29Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
* Some codes does not follow the [https://docs.google.com/a/ncsu.edu/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;.&lt;br /&gt;
*&amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; has all seven methods in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; with same name. we found these functions are completely achieved via &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;. And after test, we prove that codes in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; never got executed when we ran the project.&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we need to change some references to the method:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
verify method: 'post', :only =&amp;gt; [:destroy, :create, :update],&lt;br /&gt;
:redirect_to =&amp;gt; {:action =&amp;gt; :index}&lt;br /&gt;
&lt;br /&gt;
SignUpTopic.reassign_topic(@user_id,params[:assignment_id], params[:id])&lt;br /&gt;
redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&lt;br /&gt;
signup_team(@assignment.id, @user_id, params[:id])&lt;br /&gt;
redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is as following picture, there is a &amp;lt;code&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:originPopup.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
The new popup menu is:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:Example.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
After modifying, the other assignment functions all works well.&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:AssignTopic.png]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name &amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;code&amp;gt;signup_sheet_controller&amp;lt;/code&amp;gt; automatically.&amp;lt;br&amp;gt;&lt;br /&gt;
Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95241</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95241"/>
		<updated>2015-03-21T22:04:43Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
* Some codes does not follow the [https://docs.google.com/a/ncsu.edu/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;.&lt;br /&gt;
*&amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; has all seven methods in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; with same name. we found these functions are completely achieved via &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;. And after test, we prove that codes in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; never got executed when we ran the project.&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we need to change some references to the method:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
verify method: 'post', :only =&amp;gt; [:destroy, :create, :update],&lt;br /&gt;
:redirect_to =&amp;gt; {:action =&amp;gt; :index}&lt;br /&gt;
&lt;br /&gt;
SignUpTopic.reassign_topic(@user_id,params[:assignment_id], params[:id])&lt;br /&gt;
redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is as following picture, there is a &amp;lt;code&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:originPopup.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
The new popup menu is:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:Example.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
After modifying, the other assignment functions all works well.&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:AssignTopic.png]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name &amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;code&amp;gt;signup_sheet_controller&amp;lt;/code&amp;gt; automatically.&amp;lt;br&amp;gt;&lt;br /&gt;
Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95240</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95240"/>
		<updated>2015-03-21T22:04:14Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
* Some codes does not follow the [https://docs.google.com/a/ncsu.edu/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;.&lt;br /&gt;
*&amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; has all seven methods in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; with same name. we found these functions are completely achieved via &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;. And after test, we prove that codes in &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; never got executed when we ran the project.&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we need to change some references to the method:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  verify method: 'post', :only =&amp;gt; [:destroy, :create, :update],&lt;br /&gt;
    :redirect_to =&amp;gt; {:action =&amp;gt; :index}&lt;br /&gt;
&lt;br /&gt;
  SignUpTopic.reassign_topic(@user_id,params[:assignment_id], params[:id])&lt;br /&gt;
  redirect_to action: 'index', id: params[:assignment_id]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is as following picture, there is a &amp;lt;code&amp;gt;:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:originPopup.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
The new popup menu is:&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:Example.jpg]]&amp;lt;br&amp;gt;&lt;br /&gt;
After modifying, the other assignment functions all works well.&amp;lt;br&amp;gt;&lt;br /&gt;
[[File:AssignTopic.png]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name &amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;code&amp;gt;signup_sheet_controller&amp;lt;/code&amp;gt; automatically.&amp;lt;br&amp;gt;&lt;br /&gt;
Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95213</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95213"/>
		<updated>2015-03-21T21:39:50Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Following global rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
* Some codes does not follow the &amp;lt;b&amp;gt;Global Rules&amp;lt;/b&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is:&lt;br /&gt;
[[File:originPopup.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name &amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;code&amp;gt;signup_sheet_controller&amp;lt;/code&amp;gt; automatically.&amp;lt;br&amp;gt;&lt;br /&gt;
Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95209</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95209"/>
		<updated>2015-03-21T21:39:06Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* What's wrong with it */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
* Some codes does not follow the &amp;lt;b&amp;gt;Global Rules&amp;lt;/b&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is:&lt;br /&gt;
[[File:originPopup.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name &amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;code&amp;gt;signup_sheet_controller&amp;lt;/code&amp;gt; automatically.&amp;lt;br&amp;gt;&lt;br /&gt;
Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95200</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95200"/>
		<updated>2015-03-21T21:32:22Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; is much longer, and has many more recent mods, but some methods of &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; seem more sophisticated than &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;edit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;, etc.  Functionality is divided differently than in a standard controller.&amp;lt;br&amp;gt;a. &amp;lt;code&amp;gt;def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; b. &amp;lt;code&amp;gt;def delete_signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; c.&amp;lt;code&amp;gt;def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; d. &amp;lt;code&amp;gt;def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;e. &amp;lt;code&amp;gt;def signup&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt; f. &amp;lt;code&amp;gt;def slotAvailable?(topic_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to &amp;lt;code&amp;gt;SignupController&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is:&lt;br /&gt;
[[File:originPopup.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name&amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;signup_sheet_controller&amp;gt; automatically. Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95187</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95187"/>
		<updated>2015-03-21T21:26:04Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    &amp;lt;b&amp;gt;update_topic_info(topic)&amp;lt;/b&amp;gt;&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt;&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is:&lt;br /&gt;
[[File:originPopup.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name&amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;signup_sheet_controller&amp;gt; automatically. Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95182</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95182"/>
		<updated>2015-03-21T21:22:57Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  ...&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
the origin popup menu is:&lt;br /&gt;
[[File:Example.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a controller should be a singular noun. However, here &amp;lt;code&amp;gt;SignUp&amp;lt;/code&amp;gt; in camel case is a verb. We should modify it to a noun written as &amp;lt;code&amp;gt;Signup&amp;lt;/code&amp;gt;. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name&amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;signup_sheet_controller&amp;gt; automatically. Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95177</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95177"/>
		<updated>2015-03-21T21:18:23Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Removing unused controller */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file.&amp;lt;p&amp;gt;The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the Controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a Controller should be a singular noun. However, here SignUp in camel case is a verb. We should modify it to a noun written as Signup. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name&amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;signup_sheet_controller&amp;gt; automatically. Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95175</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95175"/>
		<updated>2015-03-21T21:17:20Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
   The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the Controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a Controller should be a singular noun. However, here SignUp in camel case is a verb. We should modify it to a noun written as Signup. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name&amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;signup_sheet_controller&amp;gt; automatically. Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95173</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95173"/>
		<updated>2015-03-21T21:15:35Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Following global rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
   The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
According to the Controller name convention&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/action_controller_overview.html&amp;lt;/ref&amp;gt;, a Controller should be a singular noun. However, here SignUp in camel case is a verb. We should modify it to a noun written as Signup. As a result, we rename all class name &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SignupSheetController&amp;lt;/code&amp;gt;. Then the controller name&amp;lt;code&amp;gt;sign_up_sheet_controller&amp;lt;/code&amp;gt; is revised into &amp;lt;signup_sheet_controller&amp;gt; automatically. Here we also make sure every reference for this controller has been changed to match the new controller name. For example, in &amp;lt;code&amp;gt;views/signup_sheet/_action.html.erb&amp;lt;/code&amp;gt; file, we must make sure this render path is correct as follows:  &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;%= render :partial =&amp;gt; '/signup_sheet/all_actions', :locals =&amp;gt; {:i=&amp;gt;i, :topic=&amp;gt;topic} %&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95171</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95171"/>
		<updated>2015-03-21T21:15:12Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Following global rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
   The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered',:id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95170</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95170"/>
		<updated>2015-03-21T21:14:41Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Following global rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
   The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are some of what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95169</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95169"/>
		<updated>2015-03-21T21:14:19Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Following global rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
After various analysis and test, we found &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; is never used. So we remove it. The reasons are listed as follows:&lt;br /&gt;
* There is no code about &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt; file. &lt;br /&gt;
   The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views&amp;lt;ref&amp;gt;http://guides.rubyonrails.org/routing.html#the-purpose-of-the-rails-router&amp;lt;/ref&amp;gt;. Rails default routing is resource routing, which allows us to declare all the common routes for a resourceful controller. In our &amp;lt;code&amp;gt;route.rb&amp;lt;/code&amp;gt;, we found a matching resourceful route for &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt;, which asks the router to map it to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; action. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  resources :signup_sheet &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This route creates several different routes in the application, all mapping to the &amp;lt;code&amp;gt;SignUpSheetController&amp;lt;/code&amp;gt; controller. &lt;br /&gt;
Here are some examples:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:13%;&amp;quot;|HTTP Verb&lt;br /&gt;
! style=&amp;quot;width:33%;&amp;quot;|Controller#Action&lt;br /&gt;
! style=&amp;quot;width:43%;&amp;quot;|Used For &lt;br /&gt;
|- style=&amp;quot;vertical-align:top;&amp;quot;&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#signup&lt;br /&gt;
| This function lets the user choose a particular topic.&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#delete_signup&lt;br /&gt;
| This function is used to delete a previous signup&lt;br /&gt;
|-&lt;br /&gt;
| GET&lt;br /&gt;
| sigh_up_sheet#view_publishing_rights&lt;br /&gt;
| The function is to make sure the publishing rights for a user&lt;br /&gt;
|}&lt;br /&gt;
However, there is not a matching route for &amp;lt;code&amp;gt;SignUpController&amp;lt;/code&amp;gt;&lt;br /&gt;
*&lt;br /&gt;
*&lt;br /&gt;
&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in&amp;lt;code&amp;gt; sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;signup_sheet_controller.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in &amp;lt;code&amp;gt;sign_up_topic.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&amp;lt;br&amp;gt;&lt;br /&gt;
We delete the following lines in &amp;lt;code&amp;gt;app/views/tree_display/actions/_assignments_actions.html.erb&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), &lt;br /&gt;
            :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; &lt;br /&gt;
            'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
----&lt;br /&gt;
According to Global Rules, there are some codes that need some improvements to make it follow the rules correctly. Here are what we have done:&lt;br /&gt;
 &lt;br /&gt;
* change &amp;lt;code&amp;gt;users_team.size == 0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;users_team.zero?&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  if users_team.size == 0&lt;br /&gt;
to:&lt;br /&gt;
  if users_team.zero?&lt;br /&gt;
or:&lt;br /&gt;
  if users_team.empty?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;key: 'value'&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;:key =&amp;gt; 'value'&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  redirect_to :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; assignment_id&lt;br /&gt;
to:&lt;br /&gt;
  redirect_to action: 'add_signup_topics_staggered', id: assignment_id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;code&amp;gt;if (var)&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;if (var == true)&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
change:&lt;br /&gt;
  (assignment.staggered_deadline == true)?&lt;br /&gt;
to:&lt;br /&gt;
  (assignment.staggered_deadline)?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95151</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95151"/>
		<updated>2015-03-21T20:50:54Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; method in the &amp;lt;code&amp;gt;SignupSheet controller&amp;lt;/code&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; button. We can see that &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;signup&amp;lt;/code&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
We delete the following lines in app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics_staggered', &lt;br /&gt;
             :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics', &lt;br /&gt;
             :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), :controller =&amp;gt; 'lottery', &lt;br /&gt;
            :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics_staggered', &lt;br /&gt;
             :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics', :id =&amp;gt; node.node_object_id}, &lt;br /&gt;
            {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95150</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95150"/>
		<updated>2015-03-21T20:48:44Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
 topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
 #if the topic already exists then update&lt;br /&gt;
 if topic&lt;br /&gt;
   update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
 SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
Before Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&amp;lt;br&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def set_duedate_info&lt;br /&gt;
 @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
 @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
 #Use this until you figure out how to initialize this array&lt;br /&gt;
 @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
 unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
 SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;. And we call these two functions in &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;update_topic_info&amp;lt;/code&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;code&amp;gt;check_after_create&amp;lt;/code&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
We delete the following lines in app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics_staggered', &lt;br /&gt;
             :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics', &lt;br /&gt;
             :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), :controller =&amp;gt; 'lottery', &lt;br /&gt;
            :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    function showIntelligentAssignmentDialog() {&lt;br /&gt;
        jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;% else %&amp;gt;&lt;br /&gt;
  &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics_staggered', &lt;br /&gt;
             :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% else %&amp;gt;&lt;br /&gt;
    &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics', :id =&amp;gt; node.node_object_id}, &lt;br /&gt;
            {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
  &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95145</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95145"/>
		<updated>2015-03-21T20:38:54Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a redundant button since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. What's more it's more reasonable to put this function in &amp;quot;Edit&amp;quot; Assignment because signup sheet is a part of the assignment. So we removed this button. Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
We delete the following lines in app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            &amp;lt;% if signup_topic %&amp;gt;&lt;br /&gt;
              &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
                &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
              &amp;lt;% else %&amp;gt;&lt;br /&gt;
                &amp;lt;%= link_to image_tag('/assets/tree_view/edit-signup-sheet-24.png', :title =&amp;gt; 'Edit signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Edit signup sheet'} %&amp;gt;&lt;br /&gt;
              &amp;lt;% end %&amp;gt;&lt;br /&gt;
              &amp;lt;% if @assignment.is_intelligent %&amp;gt;&lt;br /&gt;
                &amp;lt;%= link_to image_tag('/assets/tree_view/run-lottery.png', :title =&amp;gt; 'Assign teams intelligently', :onClick =&amp;gt; &amp;quot;showIntelligentAssignmentDialog()&amp;quot;), :controller =&amp;gt; 'lottery', :action =&amp;gt; 'run_intelligent_bid', :id =&amp;gt; @assignment.id %&amp;gt;&lt;br /&gt;
              &amp;lt;% end %&amp;gt;&lt;br /&gt;
              &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
                function showIntelligentAssignmentDialog() {&lt;br /&gt;
                    jQuery( &amp;quot;#intelligent_assignment_dialog&amp;quot; ).dialog({ closeText: &amp;quot;hide&amp;quot;, modal: true, resizable: false, width: 500 });&lt;br /&gt;
                }&lt;br /&gt;
              &amp;lt;/script&amp;gt;&lt;br /&gt;
              &amp;lt;div id=&amp;quot;intelligent_assignment_dialog&amp;quot; title=&amp;quot;Running intelligent assignment&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;p&amp;gt;Intelligent Assignment is running. Please wait for the action to be completed.&amp;lt;/p&amp;gt;&lt;br /&gt;
              &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;% else %&amp;gt;&lt;br /&gt;
              &amp;lt;% if @assignment.staggered_deadline == true %&amp;gt;&lt;br /&gt;
                &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics_staggered', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
              &amp;lt;% else %&amp;gt;&lt;br /&gt;
                &amp;lt;%= link_to image_tag('/assets/tree_view/add-signup-sheet-24.png', :title =&amp;gt; 'Add signup sheet'), {:controller =&amp;gt; 'sign_up_sheet', :action =&amp;gt; 'add_signup_topics', :id =&amp;gt; node.node_object_id}, {:title =&amp;gt; 'Add signup sheet'} %&amp;gt;&lt;br /&gt;
              &amp;lt;% end %&amp;gt;&lt;br /&gt;
            &amp;lt;% end %&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95143</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95143"/>
		<updated>2015-03-21T20:35:37Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a  since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. &lt;br /&gt;
app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95141</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95141"/>
		<updated>2015-03-21T20:31:24Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a  since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. &lt;br /&gt;
app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95140</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95140"/>
		<updated>2015-03-21T20:31:03Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
Method: &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
Method: &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a  since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. &lt;br /&gt;
app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95139</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95139"/>
		<updated>2015-03-21T20:30:29Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt;Method: index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a  since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. &lt;br /&gt;
app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95137</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95137"/>
		<updated>2015-03-21T20:29:59Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
Before Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After Refactoring:&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
----&lt;br /&gt;
When we move the mouse on the Assignment, there is a &amp;quot;Edit signup sheet&amp;quot; button in the popup menu. It is a  since there already has such a function in Assignment &amp;quot;Edit&amp;quot; menu. &lt;br /&gt;
app/views/tree_display/actions/_assignments_actions.html.erb&lt;br /&gt;
Sometimes after making some changes, the display topics function didn’t work due to some reasons. We’ve fixed those bugs and make sure it still works after our last change.&lt;br /&gt;
&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95130</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95130"/>
		<updated>2015-03-21T20:21:46Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove all the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users. This method is separated from function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; because it doesn't really do any creation works.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;check_after_create&amp;lt;/b&amp;gt; check if the assignment is a microtask and if it applies to staggered deadline. If these two conditions are met, then execute corresponding actions. These steps should be separated from &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function because it doesn't actually do works related with creation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; method, the two separated methods were called. By this way, function &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; will be much shorter and some works do not belong to it can  be finished by other methods.&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95128</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95128"/>
		<updated>2015-03-21T20:09:26Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
----&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are two examples on how these files changed.&amp;lt;br&amp;gt;&lt;br /&gt;
1. replace &amp;quot;where&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. replace &amp;quot;find_by_sql&amp;quot; in the controller with a new method in related model.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.where(assignment_id: params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       def set_duedate_info&lt;br /&gt;
         @review_rounds = Assignment.find(params[:id]).get_review_rounds&lt;br /&gt;
         @topics = SignUpTopic.find_with_assignment_id( params[:id])&lt;br /&gt;
         #Use this until you figure out how to initialize this array&lt;br /&gt;
         @duedates = SignUpTopic.find_topic_id_with_assignment_id(params[:id].to_s)&lt;br /&gt;
         unless @topics.nil?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_topic_id_with_assignment_id(aid)&lt;br /&gt;
     SignUpTopic.find_by_sql(&amp;quot;SELECT s.id as topic_id FROM sign_up_topics s WHERE s.assignment_id = &amp;quot; + aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The method &amp;lt;b&amp;gt;update_topic_info&amp;lt;/b&amp;gt; updates topics' some attributes according to received parameters, such as permitted max number of choosers and waitlisted users.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95125</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95125"/>
		<updated>2015-03-21T20:02:59Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here is an example how these file changed.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95124</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95124"/>
		<updated>2015-03-21T20:02:44Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here is an example how these file changed.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95123</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95123"/>
		<updated>2015-03-21T20:01:41Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here is an example how these file changed.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
* There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95120</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95120"/>
		<updated>2015-03-21T19:57:52Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here is an example how these file changed.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
----&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here is an example:&lt;br /&gt;
&lt;br /&gt;
* There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;Method : update_topic_info, check_after_create, create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def update_topic_info(topic)&lt;br /&gt;
  topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
  if SignedUpUser.find_with_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
    topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
  else&lt;br /&gt;
    if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
      topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def check_after_create&lt;br /&gt;
  if @assignment.is_microtask?&lt;br /&gt;
    @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
  end&lt;br /&gt;
  if @assignment.staggered_deadline?&lt;br /&gt;
    topic_set = Array.new&lt;br /&gt;
    topic = @sign_up_topic.id&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
  if topic&lt;br /&gt;
    update_topic_info(topic)&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    check_after_create&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render action: 'new', id: params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95117</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95117"/>
		<updated>2015-03-21T19:53:26Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Breaking down long methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
The controller connects the model with the view. In Rails, controllers are implemented as ActionController classes. The controller knows how to process the data that comes from the model and how to pass it onto the view. The controller should not include any database related actions (such as modifying data before it gets saved inside the database). This should be handled in the proper model. So we remove the database related functionality in the signup_sheet_controller to related models.&lt;br /&gt;
The following files were modified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
app/controllers/signup_sheet_controller.rb&lt;br /&gt;
app/models/deadline_type.rb&lt;br /&gt;
app/models/due_date.rb&lt;br /&gt;
app/models/participant.rb&lt;br /&gt;
app/models/sign_up_topic.rb&lt;br /&gt;
app/models/signed_up_user.rb&lt;br /&gt;
app/models/topic_deadline.rb&lt;br /&gt;
app/models/topic_dependency.rb&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here is an example how these file changed.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring&amp;lt;/b&amp;gt;&lt;br /&gt;
In signup_sheet_controller.rb:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def create&lt;br /&gt;
     puts &amp;quot;2222222 call create&amp;quot;&lt;br /&gt;
     topic = SignUpTopic.find_with_name_and_assignment_id(params[:topic][:topic_name], params[:id]).first&lt;br /&gt;
     #if the topic already exists then update&lt;br /&gt;
     if topic&lt;br /&gt;
       update_topic_info(topic)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also add a related method in sign_up_topic.rb&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   def find_with_name_and_assignment_id(name, aid)&lt;br /&gt;
    SignUpTopic.where(topic_name: name, assignment_id: aid)&lt;br /&gt;
   end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
We’ve find that lots of methods do more than one thing so we separate a long function into several concise functions and call them in the original function. Here are some examples:&lt;br /&gt;
&lt;br /&gt;
* There are some preparation works and check works before or after the actual create operation. So we separate two functions “update_topic_info” and “check_after_create” from “create”. And we call these two functions in “create” method instead of executing these codes directly.&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : create&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def create&lt;br /&gt;
  topic = SignUpTopic.where(topic_name: params[:topic][:topic_name], assignment_id:  params[:id]).first&lt;br /&gt;
  if topic != nil&lt;br /&gt;
    topic.topic_identifier = params[:topic][:topic_identifier]&lt;br /&gt;
    if SignedUpUser.find_by_topic_id(topic.id).nil? || topic.max_choosers == params[:topic][:max_choosers]&lt;br /&gt;
      topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
    else&lt;br /&gt;
      if topic.max_choosers.to_i &amp;lt; params[:topic][:max_choosers].to_i&lt;br /&gt;
        topic.update_waitlisted_users(params[:topic][:max_choosers])&lt;br /&gt;
        topic.max_choosers = params[:topic][:max_choosers]&lt;br /&gt;
      else&lt;br /&gt;
        flash[:error] = 'Value of maximum choosers can only be increased! No change has been made to max choosers.'&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    topic.category = params[:topic][:category]&lt;br /&gt;
    topic.save&lt;br /&gt;
    redirect_to_sign_up(params[:id])&lt;br /&gt;
  else&lt;br /&gt;
    set_values_for_new_topic&lt;br /&gt;
    if @assignment.is_microtask?&lt;br /&gt;
      @sign_up_topic.micropayment = params[:topic][:micropayment]&lt;br /&gt;
    end&lt;br /&gt;
    if @assignment.staggered_deadline?&lt;br /&gt;
      topic_set = Array.new&lt;br /&gt;
      topic = @sign_up_topic.id&lt;br /&gt;
    end&lt;br /&gt;
    if @sign_up_topic.save&lt;br /&gt;
      undo_link(&amp;quot;Topic: \&amp;quot;#{@sign_up_topic.topic_name}\&amp;quot; has been created successfully. &amp;quot;)&lt;br /&gt;
      redirect_to edit_assignment_path(@sign_up_topic.assignment_id) + &amp;quot;#tabs-5&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      render :action =&amp;gt; 'new', :id =&amp;gt; params[:id]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95115</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95115"/>
		<updated>2015-03-21T19:48:20Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some others, it is not good to combine some functions with the standard ones. For example, &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; function creates topics, which is one of the administrator’s functions. However &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; creates a record that includes information for topic and student, which happens when student clicks &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; button. We can see that &amp;lt;b&amp;gt;create&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;signup&amp;lt;/b&amp;gt; are designed for different role and different usage so it is not a good idea to combine them together.&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95110</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95110"/>
		<updated>2015-03-21T19:45:02Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;After Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : index&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95109</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95109"/>
		<updated>2015-03-21T19:44:24Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def index&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
  filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95107</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95107"/>
		<updated>2015-03-21T19:42:23Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
  @assignment_id = params[:id]&lt;br /&gt;
  @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
  @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
  @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
  @show_actions = true&lt;br /&gt;
  @priority = 0&lt;br /&gt;
  assignment=Assignment.find(params[:id])&lt;br /&gt;
        #end&lt;br /&gt;
  if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
    unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
      @show_actions = false&lt;br /&gt;
    end&lt;br /&gt;
    users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
    if users_team.size == 0&lt;br /&gt;
      @selected_topics = nil&lt;br /&gt;
    else&lt;br /&gt;
      @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
    end&lt;br /&gt;
    SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      def index&lt;br /&gt;
        puts &amp;quot;2222222 call list&amp;quot;&lt;br /&gt;
        @assignment_id = params[:id]&lt;br /&gt;
        @sign_up_topics =SignUpTopic.find_with_assignment_id( params[:id]).all&lt;br /&gt;
        filled_and_waitlisted_topics(@assignment_id)&lt;br /&gt;
        @show_actions = true&lt;br /&gt;
        @priority = 0&lt;br /&gt;
        assignment=Assignment.find(params[:id])&lt;br /&gt;
        #end&lt;br /&gt;
        if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
          unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
            @show_actions = false&lt;br /&gt;
          end&lt;br /&gt;
          #Find whether the user has signed up for any topics; if so the user won't be able to&lt;br /&gt;
          #sign up again unless the former was a waitlisted topic&lt;br /&gt;
          #if team assignment, then team id needs to be passed as parameter else the user's id&lt;br /&gt;
          users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
          if users_team.size == 0&lt;br /&gt;
            @selected_topics = nil&lt;br /&gt;
          else&lt;br /&gt;
            #TODO: fix this; cant use 0&lt;br /&gt;
            @selected_topics = SignupSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
          end&lt;br /&gt;
          SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95104</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95104"/>
		<updated>2015-03-21T19:38:59Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
&amp;lt;t&amp;gt;@assignment_id = params[:id]&lt;br /&gt;
        @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
        @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
        @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
        @show_actions = true&lt;br /&gt;
        @priority = 0&lt;br /&gt;
        assignment=Assignment.find(params[:id])&lt;br /&gt;
        #end&lt;br /&gt;
&lt;br /&gt;
        if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
          unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
            @show_actions = false&lt;br /&gt;
          end&lt;br /&gt;
&lt;br /&gt;
          #Find whether the user has signed up for any topics; if so the user won't be able to&lt;br /&gt;
          #sign up again unless the former was a waitlisted topic&lt;br /&gt;
          #if team assignment, then team id needs to be passed as parameter else the user's id&lt;br /&gt;
          users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
&lt;br /&gt;
          if users_team.size == 0&lt;br /&gt;
            @selected_topics = nil&lt;br /&gt;
          else&lt;br /&gt;
            #TODO: fix this; cant use 0&lt;br /&gt;
            @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
          end&lt;br /&gt;
&lt;br /&gt;
          SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95103</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95103"/>
		<updated>2015-03-21T19:38:32Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;SignupSheet controller&amp;lt;/b&amp;gt; is to list all the topics in the specific assignments. According to RESTful rules, a method that returns a list of all available objects should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the signup_sheet_controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before Refactoring :&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt; Method : list&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def list&lt;br /&gt;
\t@assignment_id = params[:id]&lt;br /&gt;
        @sign_up_topics = SignUpTopic.where( ['assignment_id = ?', params[:id]]).all&lt;br /&gt;
        @slots_filled = SignUpTopic.find_slots_filled(params[:id])&lt;br /&gt;
        @slots_waitlisted = SignUpTopic.find_slots_waitlisted(params[:id])&lt;br /&gt;
        @show_actions = true&lt;br /&gt;
        @priority = 0&lt;br /&gt;
        assignment=Assignment.find(params[:id])&lt;br /&gt;
        #end&lt;br /&gt;
&lt;br /&gt;
        if assignment.due_dates.find_by_deadline_type_id(1)!= nil&lt;br /&gt;
          unless !(assignment.staggered_deadline? and assignment.due_dates.find_by_deadline_type_id(1).due_at &amp;lt; Time.now )&lt;br /&gt;
            @show_actions = false&lt;br /&gt;
          end&lt;br /&gt;
&lt;br /&gt;
          #Find whether the user has signed up for any topics; if so the user won't be able to&lt;br /&gt;
          #sign up again unless the former was a waitlisted topic&lt;br /&gt;
          #if team assignment, then team id needs to be passed as parameter else the user's id&lt;br /&gt;
          users_team = SignedUpUser.find_team_users(params[:id],(session[:user].id))&lt;br /&gt;
&lt;br /&gt;
          if users_team.size == 0&lt;br /&gt;
            @selected_topics = nil&lt;br /&gt;
          else&lt;br /&gt;
            #TODO: fix this; cant use 0&lt;br /&gt;
            @selected_topics = SignUpSheetController.other_confirmed_topic_for_user(params[:id], users_team[0].t_id)&lt;br /&gt;
          end&lt;br /&gt;
&lt;br /&gt;
          SignUpTopic.remove_team(users_team, @assignment_id)&lt;br /&gt;
&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95100</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95100"/>
		<updated>2015-03-21T19:32:34Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
----&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;StudentQuizzes controller&amp;lt;/b&amp;gt; is to list all the quizzes that are available to a particular user for a particular assignment. RESTful guidelines state that a method that returns a list of all available objects, in this case the quizzes, should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the student_quizzes_controller&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95099</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95099"/>
		<updated>2015-03-21T19:32:12Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* RESTful style implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
The purpose of the &amp;lt;b&amp;gt;list&amp;lt;/b&amp;gt; method in the &amp;lt;b&amp;gt;StudentQuizzes controller&amp;lt;/b&amp;gt; is to list all the quizzes that are available to a particular user for a particular assignment. RESTful guidelines state that a method that returns a list of all available objects, in this case the quizzes, should be named as &amp;lt;b&amp;gt;index&amp;lt;/b&amp;gt;. Therefore, we renamed the list method to the index method in the controller and in all the files that had references to the list method of the student_quizzes_controller&lt;br /&gt;
&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95092</id>
		<title>CSC/ECE 517 Spring 2015/oss E1509 lds</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/oss_E1509_lds&amp;diff=95092"/>
		<updated>2015-03-21T19:22:39Z</updated>

		<summary type="html">&lt;p&gt;Jli53: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== E1509. Refactoring SignUpController and SignUpSheetController ==&lt;br /&gt;
&lt;br /&gt;
This page talks about an open source project based on Expertiza. As a part of contribution to Expertiza, this project aims to refactor SignUpController and SignUpSheetControllers.&lt;br /&gt;
&lt;br /&gt;
=== Introduction to Expertiza ===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a web application developed by Ruby on Rails framework. It serves as a peer review system for professors and students at NC State and some other colleges and universities. Students can submit different assignments and peer-review reusable learning objects (articles, code, web sites, etc)&amp;lt;ref&amp;gt;https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;. The Expertiza project is supported by the National Science Foundation. And it is an open source application and the source code can be cloned on [https://github.com/expertiza/expertiza Github] . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
===Classes involved===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
* sign_up_sheet.rb &lt;br /&gt;
* sign_up_topic.rb &lt;br /&gt;
* assignments_controller.rb&lt;br /&gt;
* response.rb&lt;br /&gt;
* and possibly other model classes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===What it does===&lt;br /&gt;
&lt;br /&gt;
Lists topics available for an assignment, checks whether a user is signed up for a topic, allows users to sign up for topics.&lt;br /&gt;
&lt;br /&gt;
===What's wrong with it===&lt;br /&gt;
* These two controllers seem to do almost the same thing.  They have many of the same methods.  SignUpSheetController is much longer, and has many more recent mods, but some methods of SignUpController seem more sophisticated than SignUpSheetController.  So, your first job is to figure out if both controllers are being used.  If not, remove the unused controller.  Or, move the functions to a single controller if that makes sense to do.&lt;br /&gt;
* Neither controller is at all RESTful; i.e.., its method names aren’t the standard names new, create, edit, delete, etc.  Functionality is divided differently than in a standard controller.&lt;br /&gt;
    a. def confirm_topic(creator_id, topic_id, assignment_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    b. def delete_signup&amp;lt;br&amp;gt;&lt;br /&gt;
    c. def delete_signup_for_topic(assignment_id,topic_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    d. def other_confirmed_topic_for_user(assignment_id, creator_id)&amp;lt;br&amp;gt;&lt;br /&gt;
    e. def signup&amp;lt;br&amp;gt;&lt;br /&gt;
    f. def slotAvailable?(topic_id)&lt;br /&gt;
* Functionality that should be in models is incorporated into the controller.&lt;br /&gt;
* Some methods are too long and appear to do more than one thing&lt;br /&gt;
* This class interfaces with assignments_controller so that a list of topics can be displayed when one is editing an assignment.  Please be careful that your changes do not affect the functionality on the Topics tab of editing an assignment.&lt;br /&gt;
* Rename the controller(s) to SignupController and/or SignupSheetController.  (“Sign up”, which gets written as SignUp in camel case, is a verb, whereas “Signup” is a noun.)&lt;br /&gt;
== Modification We Made ==&lt;br /&gt;
=== Removing unused controller ===&lt;br /&gt;
=== RESTful style implementation ===&lt;br /&gt;
=== Moving inappropriate functionality from controller to model ===&lt;br /&gt;
=== Breaking down long methods ===&lt;br /&gt;
=== Deleting redundant button ===&lt;br /&gt;
=== Renaming controller ===&lt;br /&gt;
=== Following global rules ===&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1b_10_GL&amp;diff=94313</id>
		<title>CSC/ECE 517 Spring 2015/ch1b 10 GL</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2015/ch1b_10_GL&amp;diff=94313"/>
		<updated>2015-02-19T04:12:05Z</updated>

		<summary type="html">&lt;p&gt;Jli53: /* Why using encrypted cookies */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font size=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Encrypted Cookies&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
===Background===&lt;br /&gt;
A [http://en.wikipedia.org/wiki/HTTP_cookie cookie], sometimes called HTTP cookie&amp;lt;ref&amp;gt;http://en.wikipedia.org/wiki/HTTP_cookie&amp;lt;/ref&amp;gt;, web cookie or browser cookie, is some data stored in a user’s web browser while visiting that website. Cookie is sent from web server and browser sends it back when the user loads the website, in order to notify the website of the user’s previous activity. Cookies were designed for web server to remember some user’s information or to record user’s browsing activity. (including clicking certain button, logging in, or recording which pages were visited by the user before) The most common example of this functionality is the shopping cart feature of any e-commerce site. When you visit one page of a catalog and select some items, the session cookie remembers your selection so your shopping cart will have the items you selected when you are ready to check out. Without session cookies, if you click “CHECKOUT”&lt;br /&gt;
, the new page does not recognize your past activities on prior pages and your shopping cart will always be empty&amp;lt;ref&amp;gt;http://www.allaboutcookies.org/&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In [http://rubyonrails.org/ Rails], we may get in touch with cookies when we learn session, which can be regarded as one of cookie’s usage because cookie-based session store is dramatically faster than the alternatives. Rails cookie based session storage was introduced as the default in 2007, version 2.0.0. In Rails 2 and Rails 3, the value of the cookie is a base64 encoded serialized string with an added signature. Session data is thus almost clear text. In Rails 4, the value of the cookie is an encrypted string. But if you have access to the source code of the application you can use the built-in infrastructure to decode the session.&lt;br /&gt;
&lt;br /&gt;
===Why using encrypted cookies===&lt;br /&gt;
There are some other methods that sometimes are considered to replace encrypted cookies&amp;lt;ref&amp;gt;http://pothibo.com/2013/9/sessions-and-cookies-in-ruby-on-rails&amp;lt;/ref&amp;gt;. Session data can be stored in server’s database. However this will cost more time and space when requesting session. Using cookies will dramatically increase the execution speed. &lt;br /&gt;
As for unencrypted cookie, its content can be seen without any restriction, which means anyone can see the content of cookies’ content. So it is absolutely unsafe to carry sensitive content in cookies. However, with encrypted cookies, it is possible that cookie can carry some sensitive data because the secure encryption algorithm.&lt;br /&gt;
And you probably are used to key-derivation encryption([https://github.com/codahale/bcrypt-ruby bcrypt], [http://en.wikipedia.org/wiki/PBKDF2 pbkdf2], etc). But these are not as useful as in passwords because they cannot be decrypted! However cookies need to be decrypted when they are received. So instead of a key-derivation function, Rails uses a cipher(by default [http://en.wikipedia.org/wiki/Advanced_Encryption_Standard AES-256]) to encrypt and decrypt data.&lt;br /&gt;
&lt;br /&gt;
==How it works==&lt;br /&gt;
====In Rails before 4.0====&lt;br /&gt;
=====Getting start=====&lt;br /&gt;
Firstly, let's create a Rails application in 3.2, then by default, you will see a file at &amp;lt;code&amp;gt;config/initializers/session_store.rb&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;http://big-elephants.com/2014-01/handling-rails-4-sessions-with-go/&amp;lt;/ref&amp;gt;. The contents of this file is something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;Testcookies::Application.config.session_store :cookie_store, key: '_testcookies_session'&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;:cookie_store&amp;lt;/code&amp;gt; in this line means to use cookie to store session information. And the &amp;lt;code&amp;gt;key: '_testcookies_session'&amp;lt;/code&amp;gt; is telling us to use _testcookies_session as the key to store cookie data. A single site can have cookies under different key. &lt;br /&gt;
&lt;br /&gt;
And you can add following code to controller to create a session:&lt;br /&gt;
&amp;lt;pre&amp;gt;session[:username] = 'csc517'&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Then by visiting the action that executes above code, then you can see cookies for &amp;lt;code&amp;gt;localhost:3000&amp;lt;/code&amp;gt; in Chrome Inspect Element:&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot_2015-02-17_23.31.35.png]]&lt;br /&gt;
&lt;br /&gt;
=====Deciphering content of the cookie=====&lt;br /&gt;
As you can see I have only one cookie with key &amp;lt;code&amp;gt;_testcookies_session&amp;lt;/code&amp;gt;, and the cookie has following data:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;code&amp;gt;Value: BAh7CEkiD3Nlc3Npb25faWQGOgZFVEkiJWIwMjY1Mzk0NTM3NDE1YjNkOTYyOGY1NzlmODRiNmY1BjsAVEkiDXVzZXJuYW1lBjsARkki&lt;br /&gt;
        C2NzYzUxNwY7AFRJIhBfY3NyZl90b2tlbgY7AEZJIjFYdWZNZFVVWFpYNUdYSDc1a3hybGdCS21xUW5td25majBGVmRmMWtpcVk4PQY7AEY%3D&lt;br /&gt;
        '''--fa4da3b8f5b19e25a3d4a973f94e2e0f1524b7d6'''&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The content is [http://ruby-doc.org//stdlib-2.1.2/libdoc/uri/rdoc/URI/Escape.html escaped] and [http://en.wikipedia.org/wiki/Base64 Base64] encoded data(the first two lines), followed by [http://ruby-doc.org/stdlib-2.0/libdoc/digest/rdoc/Digest.html digest] of data(the third line), which is used to make sure the content is original without modification by attackers. With lots of methods decoding Base64 codes, we are able to get the data that is stored in cookie. Let's open the rails console and try to decipher this message:&lt;br /&gt;
 &amp;lt;code&amp;gt;content = BAh7CEkiD3Nlc3Npb25faWQGOgZFVEkiJWIwMjY1Mzk0NTM3NDE1YjNkOTYyOGY1NzlmODRiNmY1BjsAVEkiDXVzZXJuYW1lBjsARkki&lt;br /&gt;
 C2NzYzUxNwY7AFRJIhBfY3NyZl90b2tlbgY7AEZJIjFYdWZNZFVVWFpYNUdYSDc1a3hybGdCS21xUW5td25majBGVmRmMWtpcVk4PQY7AEY%3D&lt;br /&gt;
 --fa4da3b8f5b19e25a3d4a973f94e2e0f1524b7d6&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the content is written to cookie it is escaped automatically. So first we need to unescape it by doing:&lt;br /&gt;
 &amp;gt;&amp;gt; content = URI.unescape(content)&lt;br /&gt;
  &amp;quot;BAh7CEkiD3Nlc3Npb25faWQGOgZFVEkiJWIwMjY1Mzk0NTM3NDE1YjNkOTYyOGY1NzlmODRiNmY1BjsAVEkiDXVzZXJuYW1lBjsARkki&lt;br /&gt;
  C2NzYzUxNwY7AFRJIhBfY3NyZl90b2tlbgY7AEZJIjFYdWZNZFVVWFpYNUdYSDc1a3hybGdCS21xUW5td25majBGVmRmMWtpcVk4PQY7AEY=&lt;br /&gt;
  --fa4da3b8f5b19e25a3d4a973f94e2e0f1524b7d6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Then the data before &amp;quot;--&amp;quot; is the real data, and after the &amp;quot;--&amp;quot; is the digest. So let's do this:&lt;br /&gt;
 &amp;gt;&amp;gt; data, digest = unescaped_content.split('--')&lt;br /&gt;
  [&amp;quot;BAh7CEkiD3Nlc3Npb25faWQGOgZFVEkiJWIwMjY1Mzk0NTM3NDE1YjNkOTYyOGY1NzlmODRiNmY1BjsAVEkiDXVzZXJuYW1lBjsARkki&lt;br /&gt;
  C2NzYzUxNwY7AFRJIhBfY3NyZl90b2tlbgY7AEZJIjFYdWZNZFVVWFpYNUdYSDc1a3hybGdCS21xUW5td25majBGVmRmMWtpcVk4PQY7AEY=&amp;quot;,&lt;br /&gt;
  &amp;quot;fa4da3b8f5b19e25a3d4a973f94e2e0f1524b7d6&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
As the data is base64 encoded, we can use this command to decode the information:&lt;br /&gt;
 &amp;gt;&amp;gt; Marshal.load(::Base64.decode64(data))&lt;br /&gt;
  {&amp;quot;session_id&amp;quot;=&amp;gt;&amp;quot;b0265394537415b3d9628f579f84b6f5&amp;quot;, &amp;quot;username&amp;quot;=&amp;gt;&amp;quot;csc517&amp;quot;, &amp;quot;_csrf_token&amp;quot;=&amp;gt;&amp;quot;XufMdUUXZX5GXH75kxrlgBKmqQnmwnfj0FVdf1kiqY8=&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
So we are able to see the data stored in the cookie: &amp;lt;code&amp;gt;&amp;quot;username&amp;quot;=&amp;gt;&amp;quot;csc517&amp;quot;&amp;lt;/code&amp;gt;. However we can’t tamper with the cookie because if we change the cookie data then the digest will not match. In order to create the digest, rails makes of use of &amp;lt;code&amp;gt;config/initializer/secret_token.rb&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 Testcookies::Application.config.secret_token = '998a88d908feae524a1f4091b3034e742bcb7863d978dc5ccc7af80f26b7129788b2c6550356c89eb452ed4f088008463239014614d0a80ac2cc0baa4de82341'&lt;br /&gt;
&lt;br /&gt;
Use this token to create digest:&lt;br /&gt;
 &amp;gt;&amp;gt;token = &amp;quot;998a88d908feae524a1f4091b3034e742bcb7863d978dc5ccc7af80f26b7129788b2c6550356c89eb452ed4f088008463239014614d0a80ac2cc0baa4de82341&amp;quot;&lt;br /&gt;
 &amp;gt;&amp;gt;OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get('SHA1').new, token, data)&lt;br /&gt;
  &amp;quot;fa4da3b8f5b19e25a3d4a973f94e2e0f1524b7d6&amp;quot;&lt;br /&gt;
&lt;br /&gt;
We can see that any changes to the data will lead to a different digest:&lt;br /&gt;
 &amp;gt;&amp;gt;data[0] = 'A'&lt;br /&gt;
 &amp;gt;&amp;gt;OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get('SHA1').new, token, data)&lt;br /&gt;
  &amp;quot;8bc1b0f49eb382b650992114264a807832496f94&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=====Using cookie with more option=====&lt;br /&gt;
In the previous example we used session to store and retrieve data from cookie. We can directly use cookie and that gives us a little bit more control. We can add these code to create a cookie:&lt;br /&gt;
 cookies[:username] = 'csc517'&lt;br /&gt;
&lt;br /&gt;
Then we can see the cookies in the browser:&lt;br /&gt;
[[File:Screenshot 2015-02-18 01.43.00.png]]&lt;br /&gt;
&lt;br /&gt;
Now there are to keys in the cookie. The first is same as before and the new one is created by the code above. One thing to notice is that the data stored for key username is not Base64encoded and it also does not have the digest. It means this type of cookie data can be tampered with by the user and the Rails application will not be able to detect that the data has been tampered with. And there are some options you can use when setting a cookies:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Option&lt;br /&gt;
! Description&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| value&lt;br /&gt;
| The cookie's value, you can also assign a list of values, such as an array.&lt;br /&gt;
|-&lt;br /&gt;
| path&lt;br /&gt;
| The application path for which this cookie applies -- the cookie won't be available for other paths. The default is the root of the application.&lt;br /&gt;
|-&lt;br /&gt;
| domain&lt;br /&gt;
| The domain for which this cookie applies; the cookie won't be available for other domains.&lt;br /&gt;
|-&lt;br /&gt;
| expires&lt;br /&gt;
| Sets the time when the cookie expires. Use a Rails Time object.&lt;br /&gt;
|-&lt;br /&gt;
| secure&lt;br /&gt;
| Indicates whether the cookie is secure; the default is false. Note: secure cookies are only sent to secure(HTTPS) servers.&lt;br /&gt;
|}&lt;br /&gt;
=====Signed cookies=====&lt;br /&gt;
Writing cookies to the response via the &amp;lt;code&amp;gt;cookies.signed&amp;lt;/code&amp;gt; has generates signed representations of cookies to prevent tampering of those cookies' values by the end user. If a signed cookie was tampered with, an &amp;lt;code&amp;gt;ActiveSupport::MessageVerifier::InvalidSignature&amp;lt;/code&amp;gt; exception will be raised.&lt;br /&gt;
 cookies.signed[:aother_username] = 'csc517'&lt;br /&gt;
Then the cookies in browser become this:&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 2015-02-18 02.03.14.png]]&lt;br /&gt;
&lt;br /&gt;
The value of &amp;lt;code&amp;gt;another_username&amp;lt;/code&amp;gt; has a digest in it, we can use that to detect whether the information has been tampered.&lt;br /&gt;
&lt;br /&gt;
=====Conclusion=====&lt;br /&gt;
Session, by default, uses signed cookies which prevents any kind of tampering of data, but the data is still visible to users. It means we can’t store sensitive information in session.It would be nice if the session data is stored in encrypted format. And in the Rails 4, the cookie is encrypted by default.&lt;br /&gt;
====In Rails 4====&lt;br /&gt;
If we generate a Rails application in Rails 4 then,by default, we will see a file at &amp;lt;code&amp;gt;config/initializers/session_store.rb&amp;lt;/code&amp;gt;. The contents of this file is something like this:&lt;br /&gt;
 Rails.application.config.session_store :cookie_store, key: '_testcookies4_session'&lt;br /&gt;
This means we use cookie to store session by default. And unlike Rails 3, now we don't have the file &amp;lt;code&amp;gt;config/initializers/secret_token.rb&amp;lt;/code&amp;gt;. Instead, we have &amp;lt;code&amp;gt;config/secrets.yml&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;http://blog.bigbinary.com/2013/03/19/cookies-on-rails.html&amp;lt;/ref&amp;gt;, and it has these content:&lt;br /&gt;
 development:&lt;br /&gt;
   secret_key_base: a760133dad846d239461e2575efa7ac44c68400ded807b58a81fa4517f87b402b76750d710a402b3a90a4b063bd2235fcea8a49186553c01a70db2fb5d4786ff&lt;br /&gt;
 test:&lt;br /&gt;
   secret_key_base: 0131c94a859126b01285f0c744e0e9759ca9aa854da3b21799e7b2d1c555f982bc31a2e7e6e1d2327cfd735587528d1fac3cc129da8cd68e6bea9cb1e6c4e5b4&lt;br /&gt;
 # Do not keep production secrets in the repository,&lt;br /&gt;
 # instead read values from the environment.&lt;br /&gt;
 production:&lt;br /&gt;
   secret_key_base: &amp;lt;%= ENV[&amp;quot;SECRET_KEY_BASE&amp;quot;] %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For each environment, the rails application has a different &amp;lt;code&amp;gt;secret_key_base&amp;lt;/code&amp;gt;. Notice that in Rails 3.2.x the key was &amp;lt;code&amp;gt;secret_token&amp;lt;/code&amp;gt;, now is &amp;lt;code&amp;gt;secret_key_base&amp;lt;/code&amp;gt;. The differences are if you only have secret_token set, your cookies will be signed, but not encrypted. This means a user cannot alter their &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt; without knowing your app's secret key, but can easily read their &amp;lt;code&amp;gt;username&amp;lt;/code&amp;gt;. This was the default for Rails 3 apps. If you have secret_key_base set, your cookies will be encrypted. This goes a step further than signed cookies in that encrypted cookies cannot be altered or read by users. This is the default starting in Rails 4.&lt;br /&gt;
&lt;br /&gt;
Let's put this code into a controller:&lt;br /&gt;
 session[:username] = 'csc517'&lt;br /&gt;
Then by visiting the action that executes above code, then you can see cookies for localhost:3000 in browser:&lt;br /&gt;
[[File:Screenshot 2015-02-18 02.29.10.png]]&lt;br /&gt;
&lt;br /&gt;
Cookie has following data:&lt;br /&gt;
 value = RjcxbnNGWVU1MnRXMWhnZ3ViOE1ObFN4SWNBaFZVaWJCUVVuWDJ0QlBxdDFpWEpBL0hxNWtRM0RpMjJYS1ROMEVkbjEyZ0piV3AxamoyVFNqUGhqTVY3engwalZFa0xFcTFwZ085cDJ&lt;br /&gt;
 wN3Q2dFp2MzlHMDVQRzM0M1RhWE9nYVVEaUJrTGFoV1paenZTMmc2WVRtandzczZCTkgzUjhGTWwweWtsM1Y3RlhjeTFMOEI0R0o5eml3ZGo3UTZQTmVOLS1PSW91Nms0YkROdUdtZWh3WE9lMDdRPT0%3D&lt;br /&gt;
 --fa205eafee14ec48d829b606cf27151e56da6c8e&lt;br /&gt;
&lt;br /&gt;
Then open &amp;lt;code&amp;gt;rails console&amp;lt;/code&amp;gt; to do the following operations:&lt;br /&gt;
 &amp;gt;&amp;gt; content = &amp;quot;RjcxbnNGWVU1MnRXMWhnZ3ViOE1ObFN4SWNBaFZVaWJCUVVuWDJ0QlBxdDFpWEpBL0hxNWtRM0RpMjJYS1ROMEVkbjEyZ0piV3AxamoyVFNqUGhqTVY3engwalZFa0xFcTFwZ085cDJ&lt;br /&gt;
 wN3Q2dFp2MzlHMDVQRzM0M1RhWE9nYVVEaUJrTGFoV1paenZTMmc2WVRtandzczZCTkgzUjhGTWwweWtsM1Y3RlhjeTFMOEI0R0o5eml3ZGo3UTZQTmVOLS1PSW91Nms0YkROdUdtZWh3WE9lMDdRPT0%3D&lt;br /&gt;
 --fa205eafee14ec48d829b606cf27151e56da6c8e&amp;quot;&lt;br /&gt;
 &amp;gt;&amp;gt; content = URI.unescape(content)&lt;br /&gt;
 &amp;gt;&amp;gt; secret_key_base = 'a760133dad846d239461e2575efa7ac44c68400ded807b58a81fa4517f87b402b76750d710a402b3a90a4b063bd2235fcea8a49186553c01a70db2fb5d4786ff'&lt;br /&gt;
 &amp;gt;&amp;gt; key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)&lt;br /&gt;
 &amp;gt;&amp;gt; key_generator = ActiveSupport::CachingKeyGenerator.new(key_generator)&lt;br /&gt;
 &amp;gt;&amp;gt; secret = key_generator.generate_key('encrypted cookie')&lt;br /&gt;
 &amp;gt;&amp;gt; sign_secret = key_generator.generate_key('signed encrypted cookie')&lt;br /&gt;
 &amp;gt;&amp;gt; encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)&lt;br /&gt;
 &amp;gt;&amp;gt; data =  encryptor.decrypt_and_verify(content)&lt;br /&gt;
 &amp;gt;&amp;gt; puts data&lt;br /&gt;
 =&amp;gt; csc517&lt;br /&gt;
&lt;br /&gt;
As you can see we need the &amp;lt;code&amp;gt;secret_key_base&amp;lt;/code&amp;gt; to make sense out of cookie data. So in Rails 4 the session data will be encrypted ,by default.&lt;br /&gt;
&lt;br /&gt;
==Attention==&lt;br /&gt;
Usually cookie has limit size which is 4K. A CookieOverflow exception is raised if you attempt to store more than 4K of data&amp;lt;ref&amp;gt;http://api.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html&amp;lt;/ref&amp;gt;.&lt;br /&gt;
If you are upgrading an existing Rails 3 app, you should leave your existing secret_token in place and simply add the new secret_key_base. Note that you should wait to set secret_key_base until you have 100% of your userbase on Rails 4 and are reasonably sure you will not need to rollback to Rails 3. This is because cookies signed based on the new secret_key_base in Rails 4 are not backwards compatible with Rails 3. You are free to leave your existing secret_token in place, not set the new secret_key_base, and ignore the deprecation warnings until you are reasonably sure that your upgrade is otherwise complete. Additionally, you should take care to make sure you are not relying on the ability to decode signed cookies generated by your app in external applications or JavaScript before upgrading. Note that changing the secret key will invalidate all existing sessions!&lt;br /&gt;
And successful encryption and signing are based on administrators’ secure operation. For example, if attackers finally have the access to secret_token or encryption key, then it is possible that they can see or modify the cookie data, then pretend to be a legal user to accomplish various operations, which is disastrous for Rails security.&lt;br /&gt;
&lt;br /&gt;
==Conclusion==&lt;br /&gt;
Cookies are used to store some small data that can notify web server of the user’s previous activity. It can be executed very quickly and will not cost much space. Encrypted cookies make sure cookies’ data will not be seen by any unauthorized users so that information security gets protected. It uses AES-256 to encrypt data by default. Using encrypted cookies sometimes will not be better if some secret keys cannot be protected properly. With access to these keys, attacker can easily see the content in cookie even modify it. So we need to pay attention to obey rules when using encrypted cookies.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jli53</name></author>
	</entry>
</feed>